使用shared_ptr和weak_ptr时避免间接循环引用
我目前正在编写一个严重依赖 shared_ptr
到目前为止,一切看起来都很好 - 我已经完成了我的 家庭作业,并对使用 shared_ptr
的一些陷阱有很好的了解。
shared_ptr
最常见的问题之一是循环依赖 - 这些问题可以通过存储不影响链上对象生命周期的 weak_ptr
来解决。然而,我很难理解有时需要通过 weak_ptr
存储指向外部对象的指针 - 我不确定它是否被禁止、不鼓励,或者是否很安全。。
下图描述了我的意思(黑色箭头表示shared_ptr
;虚线表示weak_ptr
):
替代文本 http://img694.imageshack.us/img694/6628/sharedweakptr.png
- 父级包含两个子级的
shared_ptr
,两者都使用weak_ptr
指向父级。 - 在第一个子元素的构造函数中,我通过父
weak_ptr
检索指向第二个子元素的指针并将其存储在本地。
代码如下所示:
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/enable_shared_from_this.hpp>
class child;
class child2;
class parent;
class parent : public boost::enable_shared_from_this<parent>
{
public:
void createChildren()
{
_child2 = boost::make_shared<child2>(shared_from_this());
_child = boost::make_shared<child>(shared_from_this());
}
boost::shared_ptr<child> _child;
boost::shared_ptr<child2> _child2;
};
class child
{
public:
child(boost::weak_ptr<parent> p)
{
_parent = p;
_child2 = boost::shared_ptr<parent>(p)->_child2; // is this safe?
}
boost::weak_ptr<parent> _parent;
boost::shared_ptr<child2> _child2;
};
class child2
{
public:
child2(boost::weak_ptr<parent> p)
{
this->_parent = p;
}
boost::weak_ptr<parent> _parent;
};
int main()
{
boost::shared_ptr<parent> master(boost::make_shared<parent>());
master->createChildren();
}
我已经对此进行了测试,它似乎工作正常(我没有收到任何内存泄漏的报告),但我的问题是:这安全吗?如果没有,为什么不呢?
I'm currently putting together an application that relies heavily on shared_ptr
and everything looks good so far - I've done my homework and have a pretty good idea of some of the pitfalls of using shared_ptr
s.
One of the most recognised problems with shared_ptr
is cyclic dependencies - these issues can be solved by storing weak_ptr
s that don't affect the lifetime of objects up the chain. However, I'm struggling to get my head around times where it's necessary to store a pointer to an external object via a weak_ptr
- I'm not sure whether it's forbidden, discouraged, or whether it's safe.
The following diagram describes what I mean (black arrows indicate shared_ptr
; dashed indicate weak_ptr
):
alt text http://img694.imageshack.us/img694/6628/sharedweakptr.png
- A parent contains
shared_ptr
s to two children, both of which point back to the parent using aweak_ptr
. - In the constructor of the first child I retrieve via the parent
weak_ptr
the pointer to the second child and store it locally.
The code looks like this:
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/enable_shared_from_this.hpp>
class child;
class child2;
class parent;
class parent : public boost::enable_shared_from_this<parent>
{
public:
void createChildren()
{
_child2 = boost::make_shared<child2>(shared_from_this());
_child = boost::make_shared<child>(shared_from_this());
}
boost::shared_ptr<child> _child;
boost::shared_ptr<child2> _child2;
};
class child
{
public:
child(boost::weak_ptr<parent> p)
{
_parent = p;
_child2 = boost::shared_ptr<parent>(p)->_child2; // is this safe?
}
boost::weak_ptr<parent> _parent;
boost::shared_ptr<child2> _child2;
};
class child2
{
public:
child2(boost::weak_ptr<parent> p)
{
this->_parent = p;
}
boost::weak_ptr<parent> _parent;
};
int main()
{
boost::shared_ptr<parent> master(boost::make_shared<parent>());
master->createChildren();
}
I've tested this and it seems to work ok (I don't get any reports of memory leaks), however my question is: Is this safe? And if not, why not?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
子构造函数似乎按照您调用它的方式是安全的。但总体而言并不安全。
该问题是由于在子构造函数中传入weak_ptr 作为参数造成的。这意味着您需要担心弱指针是否指向不再存在的对象。通过将此参数更改为shared_ptrs并在存储时转换为weak_ptr,我们知道该对象仍然存在。这是变化:
The child constructor appears to be safe the way you are calling it. However its not safe in general.
The issue is due to passing in a weak_ptr as the argument in the child constructor. This means you need to worry about whether the weak pointer is for an object that no-longer exists. By changing this parameter to a shared_ptrs and converting to a weak_ptr when storing we know that the object still exists. Here's the change:
错误的。 这种循环依赖存在或不存在。
如果问题存在,那么弱引用根本不是一个选择。
weak_ptr
存储指向外部对象的指针几乎从来不需要。在极少数情况下,
weak_ptr
是合适的,但大多数情况下它是shared_ptr
邪教的一部分:他们不是随机抛出shared_ptr
来解决问题,而是随机抛出一半shared_ptr
和一半weak_ptr
(如 SO 所示)。Wrong. This cyclic dependency exists or it does not.
If the issue exists, then weak reference is simply not an option.
weak_ptr
is almost never needed.There are few quite specific cases where
weak_ptr
is appropriate, but mostly it's part of theshared_ptr
cult: instead of randomly throwingshared_ptr
at problems, they randomly throw halfshared_ptr
and halfweak_ptr
(as seen on SO).如果 'p' 已经(以某种方式)被破坏,你会得到 bad_weak_ptr 异常。
因此,child ctor 期望出现异常是安全的,否则就不安全。
You'll get bad_weak_ptr exception if 'p' was (somehow) destroyed already.
So it is safe is child ctor expects exceptions and not safe otherwise.