Lets consider 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 default constructor and destructor. Does not compile. Following error occurs:
In file included from /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: In instantiation of '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 - it means, that the forward declaration of AImpl is not enough?
When adding constructor and destructor, everything works fine. What is the reason? Is it because the defaults are inlined an thus do not see the size of AImpl? And when adding constructor and destructor, the compiler assumes, that those definitions know the size of AImpl?
The unique_ptr
destructor needs to know the full definition of AImpl
, because it deletes it. So the question is, where does the unique_ptr
destructor sit? It's a template, so the question is about the instantiation point.
The destructor is instantiated 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). So the unique_ptr
destructor is instantiated where A
's constructor or destructor are placed, whichever comes first.
If you default those special members, they are generated immediately after the class body, i.e. in the header, where the size of AImpl
is not known.
If you instead declare them in the class and then put definitions (you may =default
those definitions) in the .cpp
, after the full definition of AImpl
, then the unique_ptr
destructor is instantiated there.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With