使用shared_ptr和weak_ptr时避免间接循环引用

发布于 2024-08-19 13:18:48 字数 2200 浏览 5 评论 0原文

我目前正在编写一个严重依赖 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_ptrs.

One of the most recognised problems with shared_ptr is cyclic dependencies - these issues can be solved by storing weak_ptrs 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_ptrs to two children, both of which point back to the parent using a weak_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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

身边 2024-08-26 13:18:48

子构造函数似乎按照您调用它的方式是安全的。但总体而言并不安全。

该问题是由于在子构造函数中传入weak_ptr 作为参数造成的。这意味着您需要担心弱指针是否指向不再存在的对象。通过将此参数更改为shared_ptrs并在存储时转换为weak_ptr,我们知道该对象仍然存在。这是变化:

child(boost::shared_ptr<parent> p)
{
    _parent = p;
    _child2 = p->_child2; // This is this safe
}

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:

child(boost::shared_ptr<parent> p)
{
    _parent = p;
    _child2 = p->_child2; // This is this safe
}
伤感在游骋 2024-08-26 13:18:48

shared_ptr 最常见的问题之一是循环依赖 - 这些问题可以通过存储不影响链上对象生命周期的weak_ptr 来解决。

错误的。 这种循环依赖存在或不存在。

如果问题存在,那么弱引用根本不是一个选择。

需要通过weak_ptr存储指向外部对象的指针

weak_ptr存储指向外部对象的指针几乎从来不需要。

在极少数情况下,weak_ptr 是合适的,但大多数情况下它是 shared_ptr 邪教的一部分:他们不是随机抛出 shared_ptr 来解决问题,而是随机抛出一半 shared_ptr 和一半 weak_ptr (如 SO 所示)。

One of the most recognised problems with shared_ptr is cyclic dependencies - these issues can be solved by storing weak_ptrs that don't affect the lifetime of objects up the chain.

Wrong. This cyclic dependency exists or it does not.

If the issue exists, then weak reference is simply not an option.

where it's necessary to store a pointer to an external object via a weak_ptr

weak_ptr is almost never needed.

There are few quite specific cases where weak_ptr is appropriate, but mostly it's part of the shared_ptr cult: instead of randomly throwing shared_ptr at problems, they randomly throw half shared_ptr and half weak_ptr (as seen on SO).

远山浅 2024-08-26 13:18:48

如果 '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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文