Reputation: 475
Given a class that you want to have recursive field in my case:
class SemiVariant {
union {
std::pair<SemiVariant, SemiVariant> pair_value_;
int something_else_;
}
};
Basically this can't be because obviously we have an incomplete type.
Using unique_ptr to admin the memory and allow the incomplete type also didn't work. I don't know if there already an existing class that will serve as optional
but that can use dynamic memory.
unique_ptr
are not perfect for my case because they disable the default copy constructor. Which I want to exist.
Upvotes: 1
Views: 126
Reputation:
You can write your own copyable extension to std::unique_ptr
.
template <class T>
class opaque_pointer : public std::unique_ptr < T >
{
public:
// Simple construction by moving a uniqe_ptr into it.
opaque_pointer(std::unique_ptr<T>&& rhs)
:
std::unique_ptr<T>(std::move(rhs))
{
// Print something for observation. Remember to remove it.
std::cout << "opaque_pointer(std::unique_ptr<T>&& rhs)" << endl;
}
// The copy constructor you want!
opaque_pointer(const opaque_pointer& rhs)
:
std::unique_ptr<T>(std::make_unique<T>(*rhs))
{
// Print something for observation. Remember to remove it.
std::cout << "opaque_pointer(const opaque_pointer& rhs)" << endl;
}
// It needs a move constructor too.
opaque_pointer(opaque_pointer&& rhs)
:
std::unique_ptr<T>(std::move(rhs))
{
// Print something for observation. Remember to remove it.
std::cout << "opaque_pointer(opaque_pointer&& rhs)" << endl;
}
};
Then, we can try it out.
struct Widget
{
int i;
Widget(int i) : i(i) {}
~Widget()
{
std::cout << "~Widget()" << " " << i << endl;
}
Widget& operator += (int rhs) { i += rhs; return *this; }
friend std::ostream& operator<<(std::ostream& out, const Widget& w)
{
return out << w.i;
}
};
int main()
{
std::cout << "+++ Let's try the simple constructor and copy constructor! +++" << endl;
opaque_pointer<Widget> op = make_unique<Widget>(100);
opaque_pointer<Widget> op2 = op;
*op2 += 2;
cout << "Value: " << *op << " " << *op2 << endl;
cout << "Owning: " << !!op << " " << !!op2 << endl;
std::cout << endl << "+++ Let's move it! +++" << endl;
opaque_pointer<Widget> op3 = std::move(op);
*op3 += 30;
cout << "Value: " << *op3 << endl;
cout << "Owning: " << !!op << " " << !!op3 << endl;
std::cout << endl << "+++ By the way, does it really manage life time? +++" << endl;
}
The result is like this.
+++ Let's try the simple constructor and copy constructor! +++
opaque_pointer(std::unique_ptr<T>&& rhs)
opaque_pointer(const opaque_pointer& rhs)
Value: 100 102
Owning: 1 1
+++ Let's move it! +++
opaque_pointer(opaque_pointer&& rhs)
Value: 130
Owning: 0 1
+++ By the way, does it really manage life time? +++
~Widget() 130
~Widget() 102
Upvotes: 4