你不应该真的为此使用 std::auto_ptr 。在您声明 std::auto_ptr 时,析构函数将不可见,因此可能无法正确调用它。这是假设您正在向前声明您的 pImpl 类,并在另一个文件的构造函数中创建实例。
如果您使用boost::scoped_ptr(此处不需要 shared_ptr,您将不会与任何其他对象共享 pimpl,这是由 scoped_ptr 是noncopyable强制执行的),您只需要 pimpl 析构函数在您调用时可见scoped_ptr 构造函数。
例如
// in MyClass.h
class Pimpl;
class MyClass
{
private:
std::auto_ptr<Pimpl> pimpl;
public:
MyClass();
};
// Body of these functions in MyClass.cpp
在这里,编译器会生成 MyClass 的析构函数。其中必须调用 auto_ptr 的析构函数。在 auto_ptr 析构函数被实例化的地方,Pimpl 是一个不完整的类型。所以在 auto_ptr 析构函数中,当它删除 Pimpl 对象时,它不知道如何调用 Pimpl 析构函数。
boost::scoped_ptr(和shared_ptr)没有这个问题,因为当你调用scoped_ptr(或reset方法)的构造函数时,它也会使用一个等效的函数指针,而不是调用delete。这里的关键是当 Pimpl 不是不完整类型时,它会实例化释放函数。附带说明一下,shared_ptr 允许您指定自定义解除分配函数,因此您可以将其用于 GDI 句柄或您可能想要的任何其他内容 - 但这对于您的需求来说太过分了。
如果您真的想使用 std::auto_ptr,那么您需要格外小心,确保在完全定义 Pimpl 时在 MyClass.cpp 中定义您的 MyClass 析构函数。
// in MyClass.h
class Pimpl;
class MyClass
{
private:
std::auto_ptr<Pimpl> pimpl;
public:
MyClass();
~MyClass();
};
和
// in MyClass.cpp
#include "Pimpl.h"
MyClass::MyClass() : pimpl(new Pimpl(blah))
{
}
MyClass::~MyClass()
{
// this needs to be here, even when empty
}
编译器将生成代码,在空析构函数中有效地破坏所有 MyClass 成员。所以在 auto_ptr 析构函数被实例化时,Pimpl 不再不完整,编译器现在知道如何调用析构函数。
就个人而言,我认为确保一切都正确是不值得的。还有一个风险是,稍后有人会通过删除看似多余的析构函数来整理代码。因此,对于这种事情,使用 boost::scoped_ptr 会更安全。