当使用pImpl习语时,最好使用a boost:shared_ptr
而不是std::auto_ptr
?我确定我曾经读过增强版更加异常友好吗?
class Foo { public: Foo(); private: struct impl; std::auto_ptrimpl_; }; class Foo { public: Foo(); private: struct impl; boost::shared_ptr impl_; };
[编辑]使用std :: auto_ptr <>是否总是安全的,或者是否需要使用替代的boost智能指针?
你不应该真的使用std :: auto_ptr.在声明std :: auto_ptr时,析构函数将不可见,因此可能无法正确调用它.这假设您正在声明您的pImpl类,并在另一个文件中的构造函数内创建实例.
如果您使用的boost :: scoped_ptr的(不需要的shared_ptr在这里,你将不会被共享与任何其他对象的平普尔,这是由scoped_ptr的强制执行不可复制),你只需要在平普尔析构函数调用点看到scoped_ptr构造函数.
例如
// in MyClass.h class Pimpl; class MyClass { private: std::auto_ptrpimpl; 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_ptrpimpl; 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可以更安全.
我倾向于使用auto_ptr
.一定要使你的类不可复制(声明私有拷贝ctor&operator =,否则继承boost::noncopyable
).如果你使用auto_ptr
,一个皱纹是你需要定义一个非内联析构函数,即使正文是空的.(这是因为如果让编译器生成默认的析构函数,impl
则在delete impl_
生成调用时将调用不完整的类型,调用未定义的行为).
auto_ptr
在提升指针之间几乎没有选择.如果标准库替代方案可行的话,我倾向于不在风格上使用boost.