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

med*_*106 10 c++ pimpl-idiom c++11

让我们考虑以下示例(使用c ++ 11)

A.hpp:

#include <memory>
class A
{
  public:
    //A();
    //~A();

  private:
    struct AImpl;
    std::unique_ptr<AImpl> pImpl;
};
Run Code Online (Sandbox Code Playgroud)

main.cpp中:

#include "A.hpp"

int main()
{
    A a;
}
Run Code Online (Sandbox Code Playgroud)

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

在文件中包含/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 <_Tp> :: operator()(_ Tp*)const [with _Tp = A :: AImpl]':/ usr /include/c++/4.8/bits/unique_ptr.h:184:16: 'std :: unique_ptr <_Tp,_Dp> ::〜unique_ptr()[与_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的大小?

Seb*_*edl 13

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

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

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

如果您在类中声明它们,然后在完整定义之后将定义(您可以使用=default那些定义)放入,那么析构函数将在那里实例化..cppAImplunique_ptr

  • 析构函数不需要知道大小; 内存管理负责这一点.它_does_需要知道如何破坏对象,然而,假设一个完整的类(知道是否有一个非平凡的析构函数). (3认同)