How to use unique_ptr for pimpl?

Here is a simplification of what I see when I try to use unique_ptr for pimpl. I chose unique_ptr because I really want the class to own the pointer - I want the pimpl pointer and class to have the same lifetimes.

Anyway, here is the title:

#ifndef HELP #define HELP 1 #include <memory> class Help { public: Help(int ii); ~Help() = default; private: class Impl; std::unique_ptr<Impl> _M_impl; }; #endif // HELP 

Here is the source:

 #include "Help.h" class Help::Impl { public: Impl(int ii) : _M_i{ii} { } private: int _M_i; }; Help::Help(int ii) : _M_impl{new Help::Impl{ii}} { } 

I could compile them into a library just fine. But when I try to use it in a test program, I get

 ed@bad-horse:~/ext_distribution$ ../bin/bin/g++ -std=c++0x -o test_help test_help.cpp Help.cpp In file included from /home/ed/bin/lib/gcc/x86_64-unknown-linux-gnu/4.7.0/../../../../include/c++/4.7.0/memory:86:0, from Help.h:4, from test_help.cpp:3: /home/ed/bin/lib/gcc/x86_64-unknown-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/unique_ptr.h: In instantiation of 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = Help::Impl]': /home/ed/bin/lib/gcc/x86_64-unknown-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/unique_ptr.h:245:4: required from 'void std::unique_ptr<_Tp, _Dp>::reset(std::unique_ptr<_Tp, _Dp>::pointer) [with _Tp = Help::Impl; _Dp = std::default_delete<Help::Impl>; std::unique_ptr<_Tp, _Dp>::pointer = Help::Impl*]' /home/ed/bin/lib/gcc/x86_64-unknown-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/unique_ptr.h:169:32: required from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = Help::Impl; _Dp = std::default_delete<Help::Impl>]' Help.h:6:7: required from here /home/ed/bin/lib/gcc/x86_64-unknown-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/unique_ptr.h:63:14: error: invalid application of 'sizeof' to incomplete type 'Help::Impl' 

This is a well-known security feature. I tried to follow.

My problem is that if I put the Help :: Impl declaration in the header, this would seem to eliminate any advantage of pimpl. The class layout is displayed to users. The definition is hidden, but I could do it using the help class and private members. In addition, including the Impl ad, there are new headlines that I would like to keep separate.

What am I missing? What do people put in the Impl declaration and where? Am I doing the wrong thing? Argh!

+58
c ++ c ++ 11 unique-ptr pimpl-idiom
Jan 26 2018-12-12T00:
source share
2 answers

I believe your test_help.cpp actually sees the ~Help() destructor that you declared by default. In this destructor, the compiler also tries to generate a unique_ptr destructor, but for this it needs an Impl .

So, if you move the destructor definition to Help.cpp, this problem will not go away.

- EDIT - You can also define a default destructor in the cpp file:

 Help::~Help() = default; 
+74
Jan 26 2018-12-12T00:
source share

Note this from the definition of unique_ptr :

std :: unique_ptr can be created for an incomplete type T, for example, to facilitate the use of pImpl as a descriptor. If the default removal tool is used, T must be terminated at the point in the code where the removal tool is called, which occurs in the destructor, the move assignment operator, and resets the member function std :: unique_ptr.

+5
Mar 09 '18 at 5:25
source share



All Articles