I need to write a copy constructor that also transfer the ownership of a unique_ptr member of the object being copied. The situation is as follows:
class C{
// C class stuff
};
class A{
public:
public A();
public A(const A& a);
private:
std::unique_ptr<C> c_;
}
class B{
public:
B(const A& b) : a_(a){}
private:
A a_;
};
How should I implement the copy constructor for A
?
Your intent or approach is wrong, I guess.
The copy-constructor is meant to create a copy of the argument, but since unique_ptr
maintains sole ownership one cannot make a copy of it. You could in fact make the unique_ptr member mutable
and then move the resource it points to in the copy-constructor but that would be absolutely insane (this is what std::auto_ptr
does and this is why it's deprecated).
Therefore either you need to:
unique_ptr
to shared_ptr
, but only if C is actually meant to be sharedThere's also a third option, which is to make a copy of the object pointed to by the unique_ptr in A's copy-constructor, i.e.:
A::A(const A& a) : c_(std::unique_ptr<C>(a.c_ ? new C(*a.c_) : nullptr)) {
}
Obviously you cannot just do an assignment of std::unique_ptr
s as their assignment operator is deleted. This is intentional to force the programmer to define the behavior he wants.
c_
, invalidating the original item.c_
, retaining the original items validity.c_
so that both the new and original items reference the same object.In case 1 what you're looking for is a move constructor, and the default move constructor will work fine. So you don't need to write any code, you can just do:
A temp;
A foo(std::move(temp));
Note that temp
is invalid after it is moved.
In case 2 you'll need to add a custom copy constructor to A
to create a copy of the original's c_
:
A(const A& a):c_(new C(*(a.c_))){}
After defining this in A
you can do:
A foo(A());
Note that this depends upon C
's copy constructor being functional.
In case 3 you'll need to fundamentally change A
from using a std::unique_ptr
to using a std::shared_ptr
, so the definition of c_
would become:
std::shared_ptr<C> c_;
Your construction of c_
would be identical to what you're already using for the std::unique_ptr
version of c_
. So just using the default implementations you could do:
A foo;
A bar(foo);
And now foo
and bar
point to the same C
object, and share ownership of it. This shared object will not be deleted until all shared_ptr
s referencing it have been deleted.
Technically, to
” write a copy constructor that also transfer the ownership of a unique_ptr member of the object being copied
you can just do this:
class Bad
{
private:
unique_ptr<int> p_;
public:
Bad(): p_( new int(666) ) {}
Bad( Bad& other )
: p_( move( other.p_ ) )
{}
};
Because a copy constructor can have also this signature, plus two more, in addition to the more conventional Bad( const Bad& )
.
I named that class Bad
because it's really bad, it just does not make sense to do this thing except as sabotage of someone else's code.
Instead of a copy constructor that doesn't copy,
implement a move constructor that moves, or
implement an ordinary copy constructor that copies, or
change the class design to e.g. shared ownership.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With