Pimpl with smart ptr - why do you need a constructor / destructor

Let's look at the following example (using C ++ 11)

A.hpp:

#include <memory> class A { public: //A(); //~A(); private: struct AImpl; std::unique_ptr<AImpl> pImpl; }; 

main.cpp:

 #include "A.hpp" int main() { A a; } 

Using the default constructor and destructor. Not compiled. The following error occurred:

In the file included in / usr / include / c ++ / 4.8 / memory: 81: 0, from A.hpp: 2, from main.cpp: 2: / usr / include / c ++ / 4.8 / bits / unique_ptr.h : when creating 'void std :: default_delete <_Tp> :: operator () (_ Tp *) const [with _Tp = A :: AImpl]': / usr / include / c ++ / 4.8 / bits / unique_ptr.h: 184 : 16: required from 'std :: unique_ptr <_Tp, _Dp> :: ~ unique_ptr () [with _Tp = A :: AImpl; _Dp = std :: default_delete] 'A.hpp: 3: 7: required from here / usr / include / c ++ / 4.8 / bits / unique_ptr.h: 65: 22: error: invalid application of "sizeof" to incomplete type " A :: AImpl "
static_assert (SizeOf (_Tp)> 0,

A similar error occurs when using boost :: scoped_ptr instead of std :: unique_ptr. Do I understand this correctly - does this mean that direct AImpl declaration is not enough?

When adding a constructor and destructor, everything works fine. What is the reason? Is this because the default values ​​are built-in and therefore cannot see the AImpl size? And when adding a constructor and a destructor, does the compiler assume that these definitions know the size of AImpl?

+8
c ++ c ++ 11 pimpl-idiom
source share
1 answer

The unique_ptr destructor must know the full definition of AImpl as it removes it. So the question is, where is the unique_ptr destructor unique_ptr ? This is a template, so the question is about the instantiation point.

The destructor is created when it is first used. Both the constructor and the destructor of the containing class use it (the constructor needs it if its body throws an exception). Thus, the unique_ptr destructor is created where the constructor or destructor of A , whichever comes first.

If you default these special members, they are generated immediately after the class body, that is, in the header, where the size of AImpl unknown.

If you instead declare them in a class and then put the definitions (you can =default these definitions) in .cpp , after the AImpl fully defined, a AImpl instance is created there.

+11
source share

All Articles