2

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?

fateflame
  • 157
  • 1
  • 8
  • The linked question explains it – Lightness Races in Orbit May 07 '19 at 10:03
  • 1
    Possible duplicate of [Is std::unique\_ptr required to know the full definition of T?](https://stackoverflow.com/questions/6012157/is-stdunique-ptrt-required-to-know-the-full-definition-of-t) – aparpara May 07 '19 at 10:10
  • Calling `Bag::~Bag()` will call `std::unique_ptr::~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: https://stackoverflow.com/a/6089065/5754656: The destructor for `std::unique_ptr` requires a complete definition for `T`. – Artyer May 07 '19 at 10:25
  • @Artyer thanks for you kind explanation. But I think I have already implemented destruction of `Bag` in "Bag.cpp", so I don't need to include "goods.h" again in "main.cpp" or wherever I call "~Bag()`, do I? – fateflame May 07 '19 at 11:08
  • @Artyer, in the other word, if i use a raw pointer instead of a unique_ptr, and delete `m_ptr` in ~Bag() manually, it's obviously I do not need to include "goods.h" again in "main.cpp" while `Bag` can be destructed properly. So why a unique_ptr need? – fateflame May 07 '19 at 11:12
  • 1
    Thanks @LightnessRacesinOrbit , But the explanation in the link didn't solve my question. Some more details are put in my replied comments above. – fateflame May 07 '19 at 11:16
  • 1
    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 May 07 '19 at 11:17
  • @LightnessRacesinOrbit, I've edit my question to clarify my question. Thanks for your kind advice. – fateflame May 07 '19 at 11:36

1 Answers1

2

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.

John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • I've tried to add a constructor for `Outer` but failed again. – fateflame May 08 '19 at 01:31
  • @fateflame: It's the correct solution. If it's still not working please post the full, exact content of the latest files you're having trouble with. – John Zwinck May 08 '19 at 01:39
  • Thanks a lot John. I added a default constructor in the definition of class and failed(I know it's my fault XD). And when I move the implementation of constructor to cpp file, it succeed. Now I understand why compiler always complain about missing complete definiation of class `Inner` .Thank you! – fateflame May 08 '19 at 02:03