2017-09-30 262 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