2017-09-30 196 views
0

下面的代码给出了预期的分段错误。从此指针创建共享指针

struct B{ 
    shared_ptr<B> createShared(){ return shared_ptr<B>(this);} 
}; 

int main() 
{ 
    shared_ptr<B> p1 = make_shared<B>(); 
    shared_ptr<B> p2 = p1->createShared(); 
    return 0; 
} 

但是当我改变代码

shared_ptr<B> p1 = make_shared<B>(); 
     to 
shared_ptr<B> p1(new B); 

程序编译,没有任何崩溃运行。

有人可以解释我究竟究竟是什么导致了这两种情况之间的行为改变。

注意: -我知道这不是从这个指针创建共享指针的正确方法,我所寻找的是这两种情况之间行为改变的原因。我使用的编译器是clang ++ - 3.8和g ++ - 5.4。

+2

您应该阅读['std :: enable_shared_from_this'](http://en.cppreference.com/w/cpp/memory/enable_shared_from_this)。这个引用也解释了代码中会发生什么,比如你的'createShared'函数(提示:它会导致*未定义的行为*)。 –

回答

0

没有崩溃运行并不意味着你的程序是正确的。当你点击未定义的行为时,结果是未定义的。你的程序的两个版本都销毁同一个对象两次,因为你基本上从相同的原始指针创建了两个单独的shared_ptrs。所以其中一个尝试删除导致未定义行为的无效指针。

创建shared_ptr的两种方式实际上有所不同。我们考虑shared_ptr<B> p1(new B);,它首先分配一个B,然后将原始ptr的shared_ptr初始化为B.在shared_ptr的初始化过程中,分配一个包含使用计数和同步对象的控制块。这是两个单独的分配。然而,分配一个足够大的单个块来保存控制块和实际对象,所以得到的内存布局有点不同,清理代码也略有不同。

正如一些程序员哥们提到你应该使用std::enable_shared_from_this

+0

我明白在这两种情况下,同一个对象正在被拖垮两次。基本上我在寻找的是两种情况之间的变化。如果你说在一种情况下,删除在一种情况下被调用两次,而在其他情况下则不是,那么调用或不调用删除两次的决定因素是什么。我认为这不可能是一个非常通用的情况,因为在两种情况下都会调用delete,我们只是通过任一方式创建共享指针 –

+0

我添加了一段解释两个构造之间差异的段落。不过,我也认为你应该认识到试图解释未定义行为的行为实际上是毫无意义的。每次运行程序时都不能依赖它。 – Eelke