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

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

<分区>

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

A.hpp:

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

  private:
    struct AImpl;
    std::unique_ptr<AImpl> pImpl;
};

主要.cpp:

#include "A.hpp"

int main()
{
    A a;
}

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

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,

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

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

最佳答案

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

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

如果您默认这些特殊成员,它们将在类主体之后立即生成,即在 header 中生成,其中 AImpl 的大小未知。

如果你改为在类中声明它们,然后将定义(你可以 =default 那些定义)放在 .cpp 中,在 的完整定义之后AImpl,然后 unique_ptr 析构函数在那里被实例化。

关于c++ - Pimpl with smart ptr - 为什么需要构造函数/析构函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21699201/

相关文章:

c++ - atof() 返回 float 而不是 double

c++ - WIN32显示图像,为什么不显示?

c++ - 位掩码取决于数据类型

c++ - std::string 到 std::regex

c++ - std::move 对堆栈变量有意义吗

c++ - C++ 中 std::resize(n) 和 std::shrink_to_fit 的区别?

c++ - 如何通过模板参数的可变列表向后迭代(递归)?

c++ - 在库中隐藏模板函数声明

c++ - 您使用什么模式来分离 C++ 中的接口(interface)和实现?

c++ - 将 pimpl 与模板类和显式实例化模板一起使用