Pimpl with smart ptr - 为什么需要构造函数/析构函数

时间:2014-02-11 10:27:05

标签: c++ c++11 pimpl-idiom

让我们考虑以下示例(使用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;
}

使用默认构造函数和析构函数。不编译。发生以下错误:

  

在/usr/include/c++/4.8/memory:81:0中包含的文件中,                    来自A.hpp:2,                    来自main.cpp:2:/usr/include/c++/4.8/bits/unique_ptr.h:在'void的实例化中   std :: default_delete&lt; _Tp&gt; :: operator()(_ Tp *)const [with _Tp =   A :: AImpl]':/ usr /include/c++/4.8/bits/unique_ptr.h:184:16:必需   来自'std :: unique_ptr&lt; _Tp,_Dp&gt; ::〜unique_ptr()[with _Tp = A :: AImpl;   _Dp = std :: default_delete]'A.hpp:3:7:从这里要求/usr/include/c++/4.8/bits/unique_ptr.h:65:22:错误:无效   将'sizeof'应用于不完整类型'A :: AImpl'
  static_assert(的sizeof(_TP)大于0,

使用boost :: scoped_ptr而不是std :: unique_ptr时会发生类似的错误。我是否理解正确 - 这意味着,AImpl的前向声明是不够的?

添加构造函数和析构函数时,一切正常。是什么原因?是因为默认是内联的,因此看不到AImpl的大小?在添加构造函数和析构函数时,编译器假定这些定义知道AImpl的大小?

1 个答案:

答案 0 :(得分:13)

unique_ptr析构函数需要知道AImpl的完整定义,因为它会删除它。所以问题是,unique_ptr析构函数在哪里?这是一个模板,所以问题是关于实例化点。

析构函数在首次使用时会被实例化。包含类的构造函数和析构函数都使用它(如果构造函数的主体抛出异常,则构造函数需要它)。因此,unique_ptr析构函数被实例化,其中放置了A的构造函数或析构函数,以先到者为准。

如果您默认这些特殊成员,则会立即在类主体后生成它们,即在标题中生成AImpl的大小。

如果您在类中声明它们,然后在=default的完整定义之后在.cpp中放置定义(您可以AImpl这些定义),那么{{1在那里实例化析构函数。

相关问题