2016-07-26 22 views
4

我是新來的智能指針,我試圖繞過我的頭爲什麼weak_ptr會在解除引用操作符後過期。我用來測試的代碼是在這裏:C++ weak_ptr在解除引用後過期嗎?

#include <memory> 
#include <iostream> 
#include <vector> 

using namespace std; 

struct node 
{ 
    weak_ptr<node> parent; 
    shared_ptr<node> child; 
    int val; 
}; 

shared_ptr<node> foo() 
{ 
    shared_ptr<node> a = make_shared<node>(); 
    shared_ptr<node> b = make_shared<node>(); 

    a->val = 30; 
    b->val = 20; 

    b->parent = a; 
    a->child = b; 

    return a; 
} 

int main() 
{ 
    shared_ptr<node> c = foo(); 
    node d = *foo(); 

    if (c->child->parent.expired()) 
    { 
     cout << "weak ptr in c has expired." << endl; 
    } 

    if (d.child->parent.expired()) 
    { 
     cout << "weak ptr in d has expired." << endl; 
    } 

    return 0; 
} 

方案產出weak ptr in d has expired.

我不明白爲什麼當d使用引用操作,它過期。在這方面,是否有防止它(除了不引用它)?


我試圖as mrtnj suggested通過改變節點weak_ptrshared_ptr,但我想我有一個內存泄漏。我改變了node

struct node 
{ 
    shared_ptr<node> parent; 
    shared_ptr<node> child; 
    int val; 
}; 

,然後進行修改的源代碼以添加tryCreate功能。

void tryCreate() 
{ 
    node d = *foo(); 
} 

,然後把它稱爲我main這樣,我的主要的樣子

int main() 
{ 
    tryCreate(); 
    return 0; 
} 

我使用的Visual Studio 2015年的內存分析,發現有隻分配和釋放操作沒有。我將parent更改爲weak_ptr,我看到了釋放。我做錯了什麼,或者確實需要在這些循環條件下使用weak_ptr

回答

6

A weak_ptr過期時最後shared_ptr指的是對象,被銷燬。

在你的代碼,這種情況發生在聲明

node d = *foo(); 

這裏foo()返回shared_ptr,這是最後shared_ptr是指對象(通過foo創建的兩個的父對象)。而這shared_ptr是一個臨時的,在去除後,在那裏被摧毀。這將參考計數減少到0並且weak_ptr到期。

由於shared_ptr是最後一個,因此對象被銷燬,導致其子對象也被銷燬。因此,深入研究這些對象的後面的代碼具有未定義的行爲。

由於d包含子節點的shared_ptr,此時子節點不會被銷燬,正如Miles Budnek在註釋中所述。

+0

我敢肯定,子節點不會被銷燬,因爲在語句結尾處銷燬原始父元素之前將'foo'中分配的父節點的'child'指針複製到'd' 。 –

+0

@MilesBudnek:你說得對。謝謝!我非常需要咖啡(和睡眠)。 ;-) –

2

這裏:

node d = *foo(); 

取消引用shared_ptr的,所以d包含node副本這是在中foo行創建:

shared_ptr<node> a = make_shared<node>(); 

a只會node d = *foo();後銷燬。這是因爲父節點只是一個weak_ptr節點。

對此,是否有阻止它(除了不引用它)?

不解除引用似乎是很好的方法。

您可以從 weak_tr<node> parent;切換到 shared_ptr<node> parent;其他解決方案將保持全球shared_ptr<node> root;這將保持對您的a的參考。但這取決於你的代碼真的在做什麼。

+0

當d析構函數被調用時,你的內存將被釋放,在你的例子中這是主要結束。這是一款經典的RAII。當需要將shared_ptr存儲在某個不應該阻止其銷燬的對象中時,weak_ptr-s通常是有用的,並且還可以用於消除指針的循環引用。 – marcinj

+0

@mrtnj我試着將父母設置爲'shared_ptr'。但是,我注意到有內存泄漏?也許我沒有讓我的概念正確。查看我對你的建議所做的修改。 – silentwf

+0

@silentwf你是對的,這是一個不好的建議,我會從答案中刪除它(刪除)。你有沒有考慮過使用根引用?請參閱示例:http://coliru.stacked-crooked.com/a/24a40dcc0178d75b – marcinj

3
node d = *foo(); 

foo返回shared_ptr這是保持在foo活着分配的父節點。

然後,您將該內容複製到d但不存儲shared_ptr,以便在語句結束時銷燬。現在沒有shared_ptr實例引用在foo中動態分配的節點實例,所以現在指向它的弱指針過期了。

解引用不是問題:問題是無法捕獲返回的shared_ptr