2016-07-26 6 views
4

私はスマートポインタを使い慣れていないので、私は弱参照子が逆参照演算子の後に期限切れになる理由を頭に入れようとしています。私がテストに使用されるコードはここにある: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は、間接参照演算子を使用する場合、有効期限が切れる理由を私は理解していません。これに関して、それを防ぐためにとにかく(逆参照しない以外の)存在はありますか?


私はshared_ptrにノードにweak_ptrを変更することにより、as mrtnj suggestedを試してみましたが、私はメモリリークを持っていると思います。私は

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

nodeクラスを変更した後tryCreate機能を追加するためにソースコードを変更しました。その後、

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

とは

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

のように私の主なルックスは、私は、Visual Studio 2015のメモリのプロファイリングを使用してのみ割り当てなし割り当て解除があったことに気づいたというのが私のmainようにしてそれを呼びました。 parentweak_ptrに変更しました。割り当てが解除されました。私は間違って何かをしていますか、実際にはこれらの循環状態でweak_ptrを使用する必要がありますか?

答えて

6

weak_ptrは、オブジェクトを参照する最後のshared_ptrが破棄されたときに期限が切れます。そのオブジェクト(fooによって作成された2つの親オブジェクト)を参照する最後のshared_ptrあるshared_ptrを返しfoo()

node d = *foo(); 

ここ声明で起こるあなたのコードで

。そして、このshared_ptrは一時的なものです。これにより、参照カウントは0になり、weak_ptrは期限切れになります。

shared_ptrが最後のものであったため、オブジェクトが破棄され、その子オブジェクトも破棄されます。したがって、これらのオブジェクトを掘り下げる後のコードでは、未定義の動作があります。

d子ノードにshared_ptrが含まれているので、コメントにマイルBudnekによって示されるように、子ノードは、この時点では破壊されません。ここで

+0

'foo'で割り当てられた親ノードからの' child'ポインタが 'd'にコピーされて元の親がステートメントの終わりに破棄される前に子ノードが破壊されないことは間違いありません。 –

+0

@MilesBudnek:そうです。ありがとう!私は真剣にコーヒー(そして睡眠)が必要です。 ;-) –

2

:shared_ptrを間接参照

node d = *foo(); 

あなたは、そうdはラインでFOOで作成されたnodeのコピーが含まれています

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

このaがちょうどnode d = *foo();後に破棄されます。これは、parentがノード内のweak_ptrだけであるためです。

これに関しては、それを防ぐためにとにかく(逆参照しない以外の)それがありますか?

逆参照は適切ではないようです。

weak_tr<node> parent;から shared_ptr<node> parent;に切り替えることができます。 その他の解決策は、への参照を保持するグローバルshared_ptr<node> root;を維持することです。しかし、あなたのコードが本当にやるべきことに依存します。

+0

デストラクタが呼び出されると、メモリが割り当て解除されます。例では、これはmainの終わりです。これは古典的なRAIIです。 weak_ptr-sは、その破壊を防ぐべきではないオブジェクトにshared_ptrを格納する必要がある場合や、ポインタの循環参照を削除する必要がある場合に、最も有用です。 – marcinj

+0

@mrtnj親を 'shared_ptr'に設定して、あなたが言ったことを試しました。しかし、私はメモリリークがあることに気づいたのですか?たぶん私のコンセプトが正しいとは思えない。あなたの提案で何をしたのか編集を参照してください。 – silentwf

+0

@silentwfあなたは正しいです、それは悪い提案でした。私は答えから取り除きます(ストライクアウト)。ルート参照の使用を検討しましたか?例:http://coliru.stacked-crooked.com/a/24a40dcc0178d75b – marcinj

3
node d = *foo(); 

foofooアライブに割り当てられた親ノードを保っているshared_ptrを返します。

次に、その内容をdにコピーしますが、shared_ptrは保存しないため、ステートメントの最後に破棄されます。 fooで動的に割り当てられたノードインスタンスを参照するshared_ptrインスタンスは存在しないため、弱ポインタ​​の参照は現在失効しています。

逆参照は問題ではありません。問題は、返されたshared_ptrをキャプチャできないことです。

関連する問題