98

I have found it useful to use forward declaration of classes in combination with std::unique_ptr as in the code below. It compiles and works with GCC, but the whole thing seem kind of strange, and I wonder if this is standard behaviour (i.e., required by the standard)? Since B isn't a complete type when I declare the unique_ptr.

A.hpp

#include <memory>

class B;

class A {
    std::unique_ptr<B> myptr;
    // B::~B() can't be seen from here
public:
    ~A();
};

A.cpp

#include "B.hpp"
//B.hpp has to be included, otherwise it doesn't work.

A::~A() = default; // without this line, it won't compile
// however, any destructor definition will do.

I suspect this has to do with the destructor (and therefore the need to call the destructor of unique_ptr<B>) is defined in a specific compilation unit (A.cpp).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Zyx 2000
  • 1,625
  • 1
  • 12
  • 18

1 Answers1

104

It's explicitly legal. The rule is that the types used to instantiate a template in the standard library must be complete, unless otherwise specified. In the case of unique_ptr, §20.7.1/5 says “[...] The template parameter T of unique_ptr may be an incomplete type.”

There are certain operations on the pointer which require a complete type; in particular, when the object will actually be destructed (at least with the default deleter). In your example, for example, if A::~A() were inline, this might cause problems. (Note that if you don't declare the destructor yourself, it will be inline. Which partially defeats the purpose of using std::unique_ptr.)

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • 9
    "Which partially defeats the purpose of using std::unique_ptr" What do you mean? Doesn't a class instance automatically delete its members if you don't declare the dtor? – TankorSmash Nov 05 '18 at 22:24
  • 3
    So, it isn't possible to create a custom template class with similar functionality to `unique_ptr` as the C++ standard defines custom rules for `unique_ptr` to let if work? – m7913d Dec 24 '19 at 12:16
  • 7
    Wow, it was the destructor causing the issues. As soon as I explicitly defined it in my .cpp file everything went away. – serg06 Jun 04 '20 at 16:18
  • How would this be fixed if A.hpp was an abstract class? – user1745995 Sep 25 '20 at 03:50