【问题标题】: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());
    };
}

【问题讨论】:

    标签: c++ boost shared-ptr


    【解决方案1】:

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

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

    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。
    猜你喜欢
    • 2013-04-16
    • 1970-01-01
    • 2011-04-19
    • 1970-01-01
    • 2010-10-11
    • 2012-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多