返回 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<ContainerC>
)
而在这个函数中:
SceneElementI* LoaderC::CreateContainer() const
return new ContainerC();
在创建shared_ptr
之前将指针转换为基类会丢失有关对象动态类型的信息。返回的指针是SceneElementI*
,它(我假设)没有enable_shared_from_this
基类,因此当该指针稍后用于初始化shared_ptr
时,无法判断它指向a 的基类也派生自 enable_shared_from_this<ContainerC>
的类型。
您可以通过这样做使第一个功能也无法工作:
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 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章