C++ std::shared\u ptr中的一个bug?
执行以下程序时会发生什么情况C++ std::shared\u ptr中的一个bug?,c++,c++11,shared-ptr,object-lifetime,C++,C++11,Shared Ptr,Object Lifetime,执行以下程序时会发生什么情况 #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;
#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和VisualStudio2015上都测试了这一点,在这两种情况下,程序都崩溃了。发生的情况是共享指针在其析构函数中递减计数,然后执行~test,它复制共享指针,递增计数,然后递减计数,从而触发对~test调用的无限递归。奇怪的是,调用reset并没有引发问题
我今天遇到这个问题是因为一些使用C++11之前版本的shared_ptr的旧代码被更新为使用std::shared_ptr,它没有双重删除错误。令我惊讶的是,std::shared_ptr使程序崩溃。这真的是std::shared\u ptr的预期行为吗 >你违反了C++对象生存期的基本规则:在生命周期结束后,你不能访问一个对象。只有当所有共享的_ptr实例都已结束其生命周期时,才能删除测试。因此,它的析构函数及其调用的所有代码都无法访问任何引用自身的共享_ptr实例 否则将调用未定义的行为。这不是shared_ptr中的错误;这是代码中的一个bug。若测试是向量中的一个对象,并试图在析构函数中访问该向量实例,那个么它也同样重要 令人恼火的是,那些可以用来工作的东西并不是因为迂腐的原因 这不是一个迂腐的理由。这是不可能的。一个测试对象不再存在;这不是一个有效的对象 它不起作用的原因与返回对堆栈变量的引用不起作用的原因相同。物体在这一点上消失了;你不能再访问它了
因此,您需要重新构造代码来处理这一事实。进入析构函数~test的唯一方法是,如果某个对象的生存期已结束,那么在该对象的生存期结束后访问该对象是UB。我没有看到交战角度。在这种情况下,您希望shared_ptr做什么?我看不出这是怎么回事。一旦进入析构函数,共享的ptr控制块上的ref计数为0。然后将其分配给本地ptr变量,该变量将ref计数再次增加到1。当它超出范围时,计数再次下降到0,您将获得第二次自由。shared_ptr没有办法知道你一直在搞恶作剧。@DavisKing std::shared_ptr可以处理指向其他事物的复杂模式的事物-当然不能,不是在一般情况下。它可以提供共享所有权,仅此而已。@DavisKing:我的意思是,我们告诉人们std::shared\u ptr可以处理指向其他事物的复杂模式。不,我们没有。复杂的指向模式通常会导致循环引用,而shared_ptr绝对无法处理循环引用。对象的生命周期结束后,您无法访问该对象。这是库规则还是核心语言规则?@curiousguy:由于共享的\u ptr的析构函数调用了\u test\u对象的析构函数,因此进一步使用该共享的\u ptr实例属于[class.cdtor]。语言规则最终归结为它取决于对象。由于标准没有定义当前正在销毁的库对象的状态,因此根据定义,它们的状态是未定义的。因此,访问它们会导致未定义的行为。您的评论比您的答案更准确。共享\u ptr的析构函数正在执行。其成员毫无疑问完好无损。它的储存绝对完好无损。声称它已经不存在并且它不是一个有效的对象似乎是不对的。对于您在评论中提到的在dtor执行过程中可以做的有限事情的观察更令人信服。考虑重写吗?