这个问题在这里已有答案:
让我们考虑以下示例(使用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:In '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()[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 回答
unique_ptr
析构函数需要知道AImpl
的完整定义,因为它会删除它 . 所以问题是,unique_ptr
析构函数在哪里?它是一个模板,所以问题是关于实例化点 .析构函数在首次使用时进行实例化 . 包含类的构造函数和析构函数都使用它(如果构造函数的主体抛出异常,则构造函数需要它) . 因此
unique_ptr
析构函数被实例化,其中放置A
的构造函数或析构函数,以先到者为准 .如果您默认这些特殊成员,则会在类主体之后立即生成它们,即在 Headers 中生成
AImpl
的大小 .如果您在类中声明它们然后在
.cpp
的完整定义之后将定义(您可以=default
这些定义)放在.cpp
中,那么unique_ptr
析构函数在那里被实例化 .