当前位置:  开发笔记 > 编程语言 > 正文

用于pImpl成语的std :: auto_ptr或boost :: shared_ptr?

如何解决《用于pImpl成语的std::auto_ptr或boost::shared_ptr?》经验,为你挑选了2个好方法。

当使用pImpl习语时,最好使用a boost:shared_ptr而不是std::auto_ptr?我确定我曾经读过增强版更加异常友好吗?

class Foo
{
public:
    Foo();
private:
    struct impl;
    std::auto_ptr impl_;
};

class Foo
{
public:
    Foo();
private:
    struct impl;
    boost::shared_ptr impl_;
};

[编辑]使用std :: auto_ptr <>是否总是安全的,或者是否需要使用替代的boost智能指针?



1> Wilka..:

你不应该真的使用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;

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;

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可以更安全.


您是否有理由在MyClass之外声明Pimpl类?我问,因为我已经养成了为pimpl对象使用私有结构的习惯.
这个答案包含错误的信息.`boost :: scoped_ptr`确实*不*使用type-erasure来捕获构造时的删除器,如`shared_ptr`.对于那个问题,`std :: unique_ptr`也没有.对于不完整类型,它们都遇到与`std :: auto_ptr`相同的问题.参见[scoped_ptr](http://www.boost.org/libs/smart_ptr/scoped_ptr.htm)和[GOTW 100](http://herbsutter.com/gotw/_100/).
这个答案还是正确的吗?至少在Boost 1.41中,看起来scoped_ptr需要定义类完成的析构函数和构造函数,并且它直接调用delete.

2> fizzer..:

我倾向于使用auto_ptr.一定要使你的类不可复制(声明私有拷贝ctor&operator =,否则继承boost::noncopyable).如果你使用auto_ptr,一个皱纹是你需要定义一个非内联析构函数,即使正文是空的.(这是因为如果让编译器生成默认的析构函数,impl则在delete impl_生成调用时将调用不完整的类型,调用未定义的行为).

auto_ptr在提升指针之间几乎没有选择.如果标准库替代方案可行的话,我倾向于不在风格上使用boost.


如果您没有用户定义的析构函数(可能是标准部分?),请您提供更多详细信息,说明为什么它是未定义的行为?
推荐阅读
kikokikolove
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有