Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does unique_ptr<T>::~unique_ptr need the definition of T?

If I have a class 'Bar':

// bar.h
class Bar
{
public:

    Bar() { }
};

that I forward declare to use with an std::unique_ptr in another class 'Foo':

// foo.h
#include <memory>

class Bar;

class Foo
{

public:

    Foo();

private:

    std::unique_ptr<Bar> bar_;
};

and whose definition I include in the implementation file of Foo:

// foo.cpp
#include "foo.h"
#include "bar.h"

Foo::Foo()
: bar_(new Bar)
{ }

I get the the compile-time error "Invalid application of 'sizeof' to an incomplete type 'Bar'".

I understand from here and here that to fix this, I can declare Foo's destructor in foo.h and move its empty definition to foo.cpp. What I don't understand is, why that fixes it. I read that std::unique_ptr sometimes requires to know the full definition of its type. It would make sense to me if I would have to include Bar from bar.h so that the unique_ptr sees its definition. But what does the destructor of Foo have to do with the visibility of Bar, and why does declaring ~Foo() in foo.h and defining it in foo.cpp silence the error?

like image 538
Peter Goldsborough Avatar asked Feb 15 '15 00:02

Peter Goldsborough


1 Answers

The destructor of unique_ptr<Bar> calls Bar::~Bar when it delete's the Bar it owns. So ~unique_ptr<Bar> needs to see Bar::~Bar.

But template methods are only instantiated at point of use.

The unique ptr is destroyed by the Foo in Foo::~Foo. If ~Foo lives where it can see the definition of ~Bar, all is good.

If you leave it to be generated by the compiler, it 'lives' in the declaration of Foo, where it cannot see ~Bar.

If you forward declare it, then do a Foo::~Foo() = default or Foo::~Foo() {} in the .cpp file after #include <bar.h>, it can see ~Bar at the point where ~std::unique_ptr<Bar> is called`, and all is good.

This matters in practice because how Bar is destroyed differs depending on if ~Bar is virtual, and if Bar has parents, and if ~Bar is private/protected it might be illegal to call.

like image 65
Yakk - Adam Nevraumont Avatar answered Nov 15 '22 11:11

Yakk - Adam Nevraumont