Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ copy constructor called at return

Tags:

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; } 
like image 450
Sobuch Avatar asked Mar 21 '19 20:03

Sobuch


People also ask

Is copy constructor called on return?

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.

In what situations a copy constructor is invoked?

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.

In which scenario is copy constructor not called?

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).

How is a copy constructor related to a function returning an object?

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.


1 Answers

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.

like image 98
NathanOliver Avatar answered Oct 02 '22 08:10

NathanOliver