82

スコット・マイヤーズの「EffectiveC++」の本を読んでいます。tr1::shared_ptr組み込みのポインタがあり、そのように動作することが言及されましたが、それらはオブジェクトを指す tr1::weak_ptrポインタの数を追跡します。tr1::shared_ptrs

これは、参照カウントとして知られています。これは、非循環データ構造でのリソースリークの防止に役立ちますが、サイクルが形成されるようなオブジェクトが2つ以上含まれtr1::shared_ptrsている場合、サイクルへのすべての外部ポインタが破棄された場合でも、サイクルは互いの参照カウントをゼロより上に保つ可能性があります。

それがtr1::weak_ptrs入ってくるところです。

私の質問は、循環データ構造が参照カウントをゼロより上にする方法です。C++プログラムの例をお願いします。問題はどのように解決されweak_ptrsますか?(繰り返しますが、例を挙げてください)。

4

5 に答える 5

128

繰り返しになりますが、「私の質問です。循環データ構造によって参照カウントがゼロを超えるようになります。C++プログラムで例を挙げて表示してweak_ptrsください。例を挙げて、問題をもう一度解決してください。」

この問題は、(概念的には)次のようなC++コードで発生します。

class A { shared_ptr<B> b; ... };
class B { shared_ptr<A> a; ... };
shared_ptr<A> x(new A);  // +1
x->b = new B;            // +1
x->b->a = x;             // +1
// Ref count of 'x' is 2.
// Ref count of 'x->b' is 1.
// When 'x' leaves the scope, there will be a memory leak:
// 2 is decremented to 1, and so both ref counts will be 1.
// (Memory is deallocated only when ref count drops to 0)

質問の2番目の部分に答えるには、参照カウントでサイクルを処理することは数学的に不可能です。したがって、weak_ptr(基本的には単純化されたバージョンのshared_ptr)を使用してサイクルの問題を解決することはできません。プログラマーはサイクルの問題を解決しています。

それを解決するには、プログラマーはオブジェクト間の所有権の関係を認識する必要があります。または、そのような所有権が自然に存在しない場合は、所有権の関係を発明する必要があります。

上記のC++コードは、AがBを所有するように変更できます。

class A { shared_ptr<B> b; ... };
class B { weak_ptr<A>   a; ... };
shared_ptr<A> x(new A); // +1
x->b = new B;           // +1
x->b->a = x;            // No +1 here
// Ref count of 'x' is 1.
// Ref count of 'x->b' is 1.
// When 'x' leaves the scope, its ref count will drop to 0.
// While destroying it, ref count of 'x->b' will drop to 0.
// So both A and B will be deallocated.

重要な質問は次のとおりです。weak_ptrプログラマーが所有権の関係を伝えることができず、特権の欠如または情報の欠如のために静的な所有権を確立できない場合に使用できますか?

答えは次のとおりです。オブジェクト間の所有権が不明確な場合、助けるweak_ptr ことはできません。サイクルがある場合、プログラマーはそれを見つけて壊さなければなりません。別の解決策は、完全なガベージコレクションを備えたプログラミング言語(Java、C#、Go、Haskellなど)を使用するか、C / C ++で動作する保守的な(=不完全な)ガベージコレクター(Boehm GCなど)を使用することです。 。

于 2011-09-19T15:48:49.060 に答える
58

shared_ptrは、参照カウントメカニズムを生のポインタにラップします。したがって、参照カウントのインスタンスごとにshared_ptr1ずつ増加します。2つのshare_ptrオブジェクトが相互に参照している場合、参照カウントがゼロになることはないため、オブジェクトが削除されることはありません。

weak_ptrを指しshared_ptrますが、参照カウントは増加しません。これは、参照が存在する場合でも、基になるオブジェクトを削除できることを意味しますweak_ptr

これが機能する方法は、基になるオブジェクトを使用したいときはいつでも、をweak_ptr使用してforを作成できることです。shared_ptrただし、オブジェクトがすでに削除されている場合は、aの空のインスタンスshared_ptrが返されます。基になるオブジェクトの参照カウントは参照によって増加しないためweak_ptr、循環参照によって基になるオブジェクトが削除されることはありません。

于 2011-02-13T14:08:37.023 に答える
21

将来の読者のために。
Atomによる説明が優れていることを指摘したいだけです。ここに動作するコードがあります

#include <memory> // and others
using namespace std;

    class B; // forward declaration 
    // for clarity, add explicit destructor to see that they are not called
    class A { public: shared_ptr<B> b; ~A() {cout << "~A()" << endl; } };  
    class B { public: shared_ptr<A> a; ~B() {cout << "~B()" << endl; } };     
    shared_ptr<A> x(new A);  //x->b share_ptr is default initialized
    x->b = make_shared<B>(); // you can't do "= new B" on shared_ptr                      
    x->b->a = x;
    cout << x.use_count() << endl;  
于 2013-09-20T03:56:30.220 に答える
9

弱いポインタは、管理対象オブジェクトを「監視」するだけです。彼らは「それを生かし続ける」ことも、その寿命に影響を与えることもありません。とは異なりshared_ptr、最後のweak_ptrオブジェクトがスコープ外になるか消えた場合でも、オブジェクトの存続期間に影響を与えないため、ポイントされたオブジェクトは引き続き存在できますweak_ptr。所有権はありません。はweak_ptr、オブジェクトが存在するかどうかを判断し、オブジェクトshared_ptrを参照するために使用できるを提供するために使用できます。

の定義はweak_ptr、比較的確実なものにするように設計されているため、結果として、を使用して直接実行できることはほとんどありませんweak_ptr。たとえば、逆参照することはできません。のどちらoperator*operator->定義されていませんweak_ptr。それを使用してオブジェクトへのポインタにアクセスすることはできません-get()関数はありません。weak_ptrs注文したコンテナに保存できるように定義された比較関数がありますが、それだけです。

于 2014-03-28T18:33:17.750 に答える
-6

上記の答えはすべて間違っています。weak_ptr循環参照を壊すために使用されるのではなく、別の目的があります。

基本的に、すべてがまたは呼び出しshared_ptr(s)によって作成された場合、管理するメモリ以外のリソースがなければ、必要になることはありません。これらの関数は、オブジェクト自体を使用して参照カウンターオブジェクトを作成し、同時にメモリが解放されます。make_shared()allocate_shared()weak_ptrshared_ptr

weak_ptrとの唯一の違いはshared_ptrweak_ptr実際のオブジェクトが解放された後も参照カウンターオブジェクトを保持できることです。結果として、実際に多くのshared_ptrオブジェクトstd::setを保持する場合、それらが十分に大きい場合、実際のオブジェクトは多くのメモリを占有します。この問題は、代わりにを使用することで解決できますweak_ptr。この場合、weak_ptrコンテナを使用する前に、コンテナに保存されている有効期限が切れていないことを確認する必要があります。

于 2011-11-10T04:00:38.537 に答える