执行以下程序时会发生什么?
#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()不会触发问题。
我今天遇到了这个问题,因为使用了一个没有这个双删除错误的前C ++ 11版本的shared_ptr的旧代码被更新为使用std :: shared_ptr。令我惊讶的是,std :: shared_ptr导致程序崩溃。这真的是std :: shared_ptr的预期行为吗?
答案 0 :(得分:8)
您违反了C ++对象生存期的基本规则:在生命周期结束后无法访问该对象。只有在所有test
个实例的生命周期结束时,才能删除shared_ptr
。因此,它的析构函数及其调用的所有代码都无法访问引用自身的任何shared_ptr
个实例。
否则会调用未定义的行为。这不是shared_ptr
中的错误;这是你代码中的一个错误。如果test
是vector<test>
中的对象并尝试访问析构函数中的vector<test>
实例,那么UB也同样多。
令人恼火的是,可以上班的事情不是出于迂腐的原因。
这不是一个“迂腐的理由”。它不可能。 a_test_object
不再存在;它不是一个有效的对象。
它不起作用的原因与返回对堆栈变量的引用不起作用的原因相同。这个目标已经消失了;你不能再访问了它。
因此,您需要重新构建代码以处理这一事实。