Sobuch
Sobuch

Reputation: 313

C++ copy constructor called at return

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;
}

Upvotes: 21

Views: 1369

Answers (1)

NathanOliver
NathanOliver

Reputation: 180490

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.

Upvotes: 33

Related Questions