2
votes

Here is a simple version of code:

//Outer.h
class Inner;

class Outer
{
    std::unique_ptr<Inner> m_ptr;
public:
    ~Outer();
}

//----------------------------------------
//Outer.cpp
#include "Outer.h"
#include "Inner.h"  //here is the full definition of class Inner

Outer::~Outer(){};

//----------------------------------------
//main.cpp
#include "Outer.h"

int main()
{
    Outer b;
    return 0;
}

When I compile "main.cpp", the compiler returns with C2338(can't delete an incomplete type) and C2027(use of undefined type 'Inner')

I have read Is std::unique_ptr required to know the full definition of T? and I know if I include "Inner.h" in "main.cpp", the problem can be solved. But why?

For a raw pointer, I can simply use forward declearation in header file(Outer.h), include implementation(Inner.h) in cpp file(Outer.cpp), delete it manully in destructor, and no need to include implementation again whevever I use it.

But for a unique_ptr, similarly I use forward declearation in header file(Outer.h), include implementation(Inner.h) in cpp file(Outer.cpp), delete it automatically in destructor(with default destructor), But why do I need to include inner class's implementation(Inner.h) again when I use it?

1
The linked question explains itLightness Races in Orbit
Calling Bag::~Bag() will call std::unique_ptr<goods>::~unique_ptr, which requires goods to be a complete type as it might call goods::~goods() (even though it doesn't actually call it as the pointer is nullptr, it is still required by the standard. With raw pointers you still have to construct and destruct at the memory pointed to). This is in the table provided by the answer to that question: stackoverflow.com/a/6089065/5754656: The destructor for std::unique_ptr<T> requires a complete definition for T.Artyer
Thanks @LightnessRacesinOrbit , But the explanation in the link didn't solve my question. Some more details are put in my replied comments above.fateflame
If the detailed explanation there did not adequately explain it, you will have to tell us what is missing, lest we simply repeat ourselves.Lightness Races in Orbit

1 Answers

2
votes

You need to define the constructor in the .cpp file, not just the destructor.

If the Outer constructor fails, it will need to destroy m_ptr, that that requires knowing the definition of class Inner.