您不应该真正使用std::auto_ptr来做这件事。在您声明std::auto_ptr时,析构函数可能不可见,因此可能无法正确调用。这是假设您正在前向声明pImpl类,并在另一个文件的构造函数中创建实例。
如果您使用boost::scoped_ptr(这里不需要shared_ptr,您不会与任何其他对象共享pimpl,并且这是通过scoped_ptr为noncopyable而强制执行的),则只需要在调用scoped_ptr构造函数时使pimpl析构函数可见。
例如:
class Pimpl;
class MyClass
;
在这里编译器将会生成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析构函数。
class Pimpl;
class MyClass
{
private:
std::auto_ptr<Pimpl> pimpl;
public:
MyClass();
~MyClass();
};
并且
#include "Pimpl.h"
MyClass::MyClass() : pimpl(new Pimpl(blah))
{
}
MyClass::~MyClass()
{
}
编译器将生成代码,在空析构函数中有效地销毁MyClass成员。因此,在实例化auto_ptr析构函数时,Pimpl不再是不完整的,并且编译器现在知道如何调用析构函数。
个人而言,我认为确保一切正确并不值得麻烦。还有一个风险,即后来有人通过删除看似多余的析构函数来整理代码。因此,对于这种情况,使用boost::scoped_ptr更加安全可靠。
scoped_ptr
、shared_ptr
、auto_ptr
或其他),而你的“shell”类仅仅是将调用转发到实现类并在其析构函数中删除指针。不知怎么的,如果shell类做了更多的事情,那么设计可能会出问题。 - Gregory Pakosz