【发布时间】:2017-10-28 15:02:30
【问题描述】:
执行以下程序时会发生什么?
#include <iostream>
#include <memory>
class test;
std::shared_ptr<test> a_test_object;
struct test
{
~test()
{
std::cout << "destroy test" << std::endl;
auto ptr = a_test_object;
}
};
int main()
{
a_test_object = std::make_shared<test>();
//a_test_object.reset(); // Uncomment this and it works fine.
}
我在 GCC 和 Visual Studio 2015 上对此进行了测试,在这两种情况下程序都崩溃了。发生的情况是共享指针在其析构函数中递减计数,然后执行 ~test(),它复制共享指针递增然后递减计数,触发对 ~test() 的无限递归调用。奇怪的是,调用 reset() 不会触发问题。
我今天遇到了这个问题,因为一些使用 pre-C++11 版本的 shared_ptr 的旧代码(没有这种双重删除错误)已更新为使用 std::shared_ptr。令我惊讶的是,std::shared_ptr 使程序崩溃。这真的是 std::shared_ptr 的预期行为吗?
【问题讨论】:
-
进入析构函数
~test的唯一方法是a_test_object的生命周期已经结束,因此在其生命周期结束后访问该对象是UB。 -
我没有看到这里的好战角度。在这种情况下,您希望 shared_ptr 做什么?
-
我不明白它是如何工作的。进入析构函数后,shared_ptr 控制块上的引用计数为 0。然后将其分配给本地 ptr 变量,该变量再次将引用计数增加到 1。当它超出范围时,计数再次降至 0,您将获得第二个空闲。 shared_ptr 无法知道你在搞恶作剧。
-
@DavisKing "std::shared_ptr 可以处理指向其他事物的复杂事物模式" - 当然不能,不是一般性。它可以提供共享所有权,仅此而已。
-
@DavisKing:“我的意思是,我们告诉人们 std::shared_ptr 可以处理指向其他事物的复杂模式。”不,我们没有。复杂的指向模式通常会导致 循环引用,
shared_ptr绝对无法处理。
标签: c++ c++11 shared-ptr object-lifetime