11

In the following code, is the only way to avoid a compile error and to include B.h implementing the move constructor / assignment manually in A.cpp?

// A.h
#include <memory>
class B; // implementation somewhere in B.h/B.cpp
class A
{
public:
    A() = default;
    ~A() = default;
    A(const A&) = delete;
    A& operator=(const A&) = delete;
    A(A&&) = default;
    A& operator=(A&&) = default;

private:
    std::unique_ptr<B> m_b;
};

Visual Studio 2015 gives "error C2027: use of undefined type", since the move constructor/assignment operator of std::unique_ptr calls the deleter on m_b (trying to invoke B's destructor), which is obviously not known at this point.

Robert
  • 767
  • 8
  • 17
  • 2
    related/dup: http://stackoverflow.com/questions/13414652/forward-declaration-with-unique-ptr – NathanOliver Nov 02 '16 at 15:16
  • 5
    I actually didn't know that you could = default in .cpp, too. I thought it was required on declaration. So the proper way of handling my specific case would simply be to declare the move constructor as A(A&&) noexcept; in A.h and define it as A::A(A&&) noexcept = default; in A.cpp. Thanks! – Robert Nov 02 '16 at 15:26
  • That sounds like a good idea. – NathanOliver Nov 02 '16 at 15:29
  • 1
    This is a better solution than the accepted answer imo. – chrisvarnz Feb 08 '18 at 17:03

1 Answers1

18

Yes, you need to have access to the full definition of B from wherever you instantiate std::unique_ptr<B>::~unique_ptr, because it needs to call B's destructor.

In your case, that means that A::~A's definition must be moved to a separate A.cpp file, which includes B.h.

laurisvr
  • 2,724
  • 6
  • 25
  • 44
Quentin
  • 62,093
  • 7
  • 131
  • 191
  • 6
    To be clear, `~A() = default;` can be moved into the cpp file as `A::~A() = default;` - there's no need to implement it manually. Same for any other methods with this issue. – Eric Feb 05 '19 at 05:51