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
。
我是智能指针的新手,我正在努力思考为什么 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
。