返回 boost::shared_ptr 和从返回的原始指针构造 boost::shared_ptr 有啥区别?

Posted

技术标签:

【中文标题】返回 boost::shared_ptr 和从返回的原始指针构造 boost::shared_ptr 有啥区别?【英文标题】:What is the difference between returning a boost::shared_ptr and constructing a boost::shared_ptr from a returned raw pointer?返回 boost::shared_ptr 和从返回的原始指针构造 boost::shared_ptr 有什么区别? 【发布时间】:2013-08-21 08:26:36 【问题描述】:

有人能告诉我这两种方法在如下使用时的区别吗?

如果我使用 CreateBoostContainer,我的代码运行良好。但是,如果我使用 CreateContainer,则稍后在尝试在 ContainerC 上使用 shared_from_this 时,函数 Foo 的代码中会出现 boost::bad_weak_ptr 异常。我只使用一个线程。

谢谢!

用法:

SceneElementNodeC* poNode(new SceneElementNodeC(CreateBoostContainer()));
SceneElementNodeC* poNode(new SceneElementNodeC(boost::shared_ptr<SceneElementI>(CreateContainer())));

定义:

boost::shared_ptr<SceneElementI> LoaderC::CreateBoostContainer() const

    return boost::shared_ptr<SceneElementI>(new ContainerC());


SceneElementI* LoaderC::CreateContainer() const

    return new ContainerC();

场景元素节点C:

class SceneElementNodeC

    SceneElementNodeC(boost::shared_ptr<SceneElementI> spSceneElement)
    : m_spSceneElement(spSceneElement)
    ;

容器C:

class ContainerC : public SceneElementI, public boost::enable_shared_from_this<ContainerC>

    ContainerC()
    ;

    void Foo(VisitorI* poVisitor)
    
        poVisitor->Visit(shared_from_this());
    ;

【问题讨论】:

【参考方案1】:

首先,CreateBoostContainer 是一个可怕的名字,Boost 库包含数百个组件,包括几个容器,shared_ptr 只是 Boost 的一小部分。如果您稍后更改代码以返回 std::shared_ptr 而不是您必须重命名函数,那么您会将其更改为 CreateStdContainer 吗?!

其次,您未能提供允许重现问题的完整代码,因此根据 *** 的规则,您的问题应该被关闭!我猜你的类型是这样定义的:

class ContainerC
: public SceneElementI, public boost::enable_shared_from_this<ContainerC>

  // ...
;

不同的是在这个函数中:

boost::shared_ptr<SceneElementI> LoaderC::CreateBoostContainer() const

    return boost::shared_ptr<SceneElementI>(new ContainerC());

您使用ContainerC* 初始化shared_ptr,因此shared_ptr 构造函数能够检测到存在enable_shared_from_this 基类(通过隐式向上转换为enable_shared_from_this&lt;ContainerC&gt;

而在这个函数中:

SceneElementI* LoaderC::CreateContainer() const

    return new ContainerC();

在创建shared_ptr 之前将指针转换为基类会丢失有关对象动态类型的信息。返回的指针是SceneElementI*,它(我假设)没有enable_shared_from_this 基类,因此当该指针稍后用于初始化shared_ptr 时,无法判断它指向a 的基类也派生自 enable_shared_from_this&lt;ContainerC&gt; 的类型。

您可以通过这样做使第一个功能也无法工作:

boost::shared_ptr<SceneElementI> LoaderC::CreateBoostContainer() const

    SceneElementI* ptr = new ContainerC();
    return boost::shared_ptr<SceneElementI>(ptr);

这是等效的,因为它在创建 shared_ptr 之前将指针转换为 SceneElement*

shared_ptr 很聪明,它利用了你构造它的指针类型,即使它不是存储在shared_ptr 中的类型,所以如果你先向上转换该指针,那么shared_ptr 就不能聪明的。

【讨论】:

首先感谢您对差异的详细说明,这正是我不明白的。 关于 CreateBoostContainer 的命名,当然很糟糕,但只是为了区分这个问题中的两个函数。关于第二点,您是对的,但我希望在这种情况下,仍然有机会改进问题(我肯定会这样做)而不是立即关闭它;)【参考方案2】:

Documentation for enable_shared_from_this

要求:enable_shared_from_this 必须是可访问的基类 T. *this 必须是 T 类型的实例 t 的子对象。那里 必须至少存在一个拥有 t 的 shared_ptr 实例 p。

注意,“必须至少存在一个拥有 t 的 shared_ptr 实例 p”。

如果您使用CreateContainer,则没有拥有它的shared_ptr 实例。

【讨论】:

构造的SceneElementNodeC拥有一个shared_pointer,所以有一个,还是我错了?【参考方案3】:

Using the raw pointer at all is poor form. 这就是为什么通常使用std::make_shared 之类的东西来防止任何可能的内存泄漏。考虑到在新建类和它与智能指针相关联之间可能会引发异常。

话虽如此,我相信这只是 boost 的 enable_shared_from_this 工作原理的一个实现细节。

【讨论】:

就算是实现细节,我用第一种还是第二种方法有什么区别?在使用 shared_from_this 的那一刻,我没有看到任何区别,即构造的 SceneElementNodeC 拥有 shared_pointer。

以上是关于返回 boost::shared_ptr 和从返回的原始指针构造 boost::shared_ptr 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

传递大数据向量的更好方法

boost库之内存管理shared_ptr

Boost智能指针——shared_ptr

类的 boost::shared_ptr 作为结构成员

boost::shared_ptr与定制删除器

boost: 使用自定义删除器序列化 shared_ptr