error: use of deleted function 'A::A(const A&)' return tmp; ^~~
Why is the copy constructor called only when there is a virtual destructor in A
? How to avoid this?
struct B {}; struct A{ std::unique_ptr<B> x; virtual ~A() = default; }; A f() { A tmp; return tmp; }
The copy constructor is called because you call by value not by reference. Therefore a new object must be instantiated from your current object since all members of the object should have the same value in the returned instance.
The copy constructor is invoked when the new object is initialized with the existing object. The object is passed as an argument to the function. It returns the object.
A copy constructor can also be defined by a user; in this case, the default copy constructor is not called. A user-defined copy constructor is generally needed when an object owns pointers or non-shareable references to a file (for example).
The function is about to return. The copy constructor is invoked. It takes a reference to the local variable. It uses this reference to copy everything into the new object that will be used as the return value.
virtual ~A() = default;
is a user declared destructor. Because of that, A
no longer has a move constructor. That means return tmp;
can't move tmp
and since tmp
is not copyable, you get a compiler error.
There are two ways you can fix this. You can add a move constructor like
struct A{ std::unique_ptr<B> x; A() = default; // you have to add this since the move constructor was added A(A&&) = default; // defaulted move virtual ~A() = default; };
or you can create a base class that has the virtual destructor and inherit from that like
struct C { virtual ~C() = default; }; struct A : C { std::unique_ptr<B> x; };
This works because A
no longer has a user declared destructor (Yes, C
does but we only care about A
) so it will still generate a move constructor in A
. The important part of this is that C
doesn't have a deleted move constructor, it just doesn't have one period, so trying to move it will cause a copy. That means C
's copy constructor is called in A
's implicitly generated move constructor since C(std::move(A_obj_to_move_from))
will copy as long as it doesn't have a deleted move constructor.
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