How do I use unique_ptr for pimpl?

自作多情 提交于 2019-11-26 10:39:18

问题


Here is a simplification of what I\'m seeing 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 lifetimes of the pimpl pointer and the class to be the same.

Anyway, here is the header:

#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 these 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 safety feature. I\'ve tried to follow.

My problem is that if I put Help::Impl declaration in a header it would seem to obviate any advantage of pimpl. The class layout is visible to users. The definition is hidden but I could have done that with the Help class and private members. Also, including the declaration of Impl brings in new headers that I would have liked to keep separate.

What am I missing? What do folks put in an Impl declaration and where? Am I doing the Help dtor wrong? Argh!


回答1:


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

So if you move the destructor definition to the Help.cpp, this problem should be gone.

-- EDIT -- You can define the destructor to be default in the cpp file, too:

Help::~Help() = default;



回答2:


Note this from unique_ptr definition:

std::unique_ptr may be constructed for an incomplete type T, such as to facilitate the use as a handle in the pImpl idiom. If the default deleter is used, T must be complete at the point in code where the deleter is invoked, which happens in the destructor, move assignment operator, and reset member function of std::unique_ptr.



来源:https://stackoverflow.com/questions/9020372/how-do-i-use-unique-ptr-for-pimpl

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!