c++ weak_ptr 在取消引用后过期?

c++ weak_ptr expiring after dereference?

我是智能指针的新手,我正在努力思考为什么 weak_ptr 在取消引用运算符后会过期。我用来测试的代码在这里:

#include <memory>
#include <iostream>
#include <vector>

using namespace std;

struct node
{
    weak_ptr<node> parent;
    shared_ptr<node> child;
    int val;
};

shared_ptr<node> foo()
{
    shared_ptr<node> a = make_shared<node>();
    shared_ptr<node> b = make_shared<node>();

    a->val = 30;
    b->val = 20;

    b->parent = a;
    a->child = b;

    return a;
}

int main()
{
    shared_ptr<node> c = foo();
    node d = *foo();

    if (c->child->parent.expired())
    {
        cout << "weak ptr in c has expired." << endl;
    }

    if (d.child->parent.expired())
    {
        cout << "weak ptr in d has expired." << endl;
    }

    return 0;
}

程序输出weak ptr in d has expired.

我不明白为什么当 d 使用取消引用运算符时,它会过期。关于这一点,有没有办法阻止它(除了不取消引用它)?


我通过将节点中的 weak_ptr 更改为 shared_ptr 来尝试 ,但我认为我有内存泄漏。我将 node class 更改为

struct node
{
    shared_ptr<node> parent;
    shared_ptr<node> child;
    int val;
};

然后修改源代码添加一个tryCreate函数。

void tryCreate()
{
    node d = *foo();
}

然后在我的 main 中调用它,这样我的主程序看起来像

int main()
{
    tryCreate();
    return 0;
}

我使用了 Visual Studio 2015 年的内存分析并注意到只有分配而没有释放。我将 parent 更改为 weak_ptr,我看到了释放。我是做错了什么还是确实需要在这些循环条件下使用 weak_ptr

当引用对象的最后一个 shared_ptr 被销毁时,weak_ptr 过期。

在您的代码中发生的语句

node d = *foo();

这里foo()returns一个shared_ptr,也就是最后一个shared_ptr引用那个对象([=16=创建的两个的父对象) ]).这个 shared_ptr 是一个临时的,在取消引用之后就在那里被销毁了。这会将引用计数减少到 0,并且 weak_ptr 过期。

由于shared_ptr是最后一个,对象被销毁,导致其子对象也被销毁。因此,后来深入研究这些对象的代码具有未定义的行为。

由于 d 包含子节点的 shared_ptr,因此子节点此时未被销毁,正如 Miles Budnek 在评论中指出的那样。

这里:

node d = *foo();

您取消引用 shared_ptr,因此 d 包含 node 的副本,该副本是在 foo 中创建的:

shared_ptr<node> a = make_shared<node>();

这个 a 将在 node d = *foo(); 之后被销毁。这是因为parent只是一个weak_ptr inside node.

In regards to this, is there anyway to prevent it (other than not dereferencing it)?

不取消引用似乎是个好方法。

您可以从 weak_tr<node> parent; 切换到 shared_ptr<node> parent; 其他解决方案是保留全局 shared_ptr<node> root;,它会保留对你的a。但这取决于您的代码真正要做什么。

node d = *foo();

foo returns a shared_ptr 使 foo 中分配的父节点保持活动状态。

然后将其内容复制到 d 但不存储 shared_ptr,因此它在语句末尾被销毁。现在没有 shared_ptr 个实例引用 foo 中动态分配的节点实例,因此指向它的弱指针引用现在已过期。

取消引用不是问题:问题是未能捕获返回的 shared_ptr