Rob*_*Rob 16 c++ boost stl auto-ptr shared-ptr
当使用pImpl习语时,最好使用a boost:shared_ptr而不是std::auto_ptr?我确定我曾经读过增强版更加异常友好吗?
class Foo
{
public:
Foo();
private:
struct impl;
std::auto_ptr<impl> impl_;
};
class Foo
{
public:
Foo();
private:
struct impl;
boost::shared_ptr<impl> impl_;
};
Run Code Online (Sandbox Code Playgroud)
[编辑]使用std :: auto_ptr <>是否总是安全的,或者是否需要使用替代的boost智能指针?
Wil*_*lka 38
你不应该真的使用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_ptr<Pimpl> pimpl;
public:
MyClass();
};
// Body of these functions in MyClass.cpp
Run Code Online (Sandbox Code Playgroud)
在这里,编译器将生成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();
};
Run Code Online (Sandbox Code Playgroud)
和
// in MyClass.cpp
#include "Pimpl.h"
MyClass::MyClass() : pimpl(new Pimpl(blah))
{
}
MyClass::~MyClass()
{
// this needs to be here, even when empty
}
Run Code Online (Sandbox Code Playgroud)
编译器将生成代码,在空析构函数中有效地"破坏"所有MyClass成员.因此,在实例化auto_ptr析构函数时,Pimpl不再是不完整的,编译器现在知道如何调用析构函数.
就个人而言,我认为确保一切都正确是不值得的.还有一种风险,即有人会稍后出现并通过删除看似多余的析构函数来整理代码.因此,对于这种事情,使用boost :: scoped_ptr可以更安全.
fiz*_*zer 12
我倾向于使用auto_ptr.一定要使你的类不可复制(声明私有拷贝ctor&operator =,否则继承boost::noncopyable).如果你使用auto_ptr,一个皱纹是你需要定义一个非内联析构函数,即使正文是空的.(这是因为如果让编译器生成默认的析构函数,impl则在delete impl_生成调用时将调用不完整的类型,调用未定义的行为).
auto_ptr在提升指针之间几乎没有选择.如果标准库替代方案可行的话,我倾向于不在风格上使用boost.