web-dev-qa-db-ja.com

共有ポインタはどのように機能しますか?

共有ポインターは、そのオブジェクトを指すポインターの数をどのように知るのですか? (この場合、shared_ptr)

40
cam

基本的に、shared_ptrには2つのポインタがあります。共有オブジェクトへのポインタと、2つの参照カウントを含む構造体へのポインタです。1つは「強い参照」または所有権を持つ参照用で、もう1つは「弱い参照」用です。所有権を持たない参照。

shared_ptrをコピーすると、コピーコンストラクターは強い参照カウントをインクリメントします。 shared_ptrを破棄すると、デストラクタは強力な参照カウントをデクリメントし、参照カウントがゼロかどうかをテストします。そうである場合、shared_ptrsが共有オブジェクトを指していないため、デストラクタは共有オブジェクトを削除します。

弱参照カウントは、weak_ptrをサポートするために使用されます。基本的に、weak_ptrshared_ptrから作成されるたびに、弱参照カウントがインクリメントされ、1つが破棄されるたびに、弱参照カウントがデクリメントされます。強参照カウントまたは弱参照カウントのいずれかがゼロより大きい限り、参照カウント構造体は破棄されません。

事実上、強い参照カウントがゼロより大きい限り、共有オブジェクトは削除されません。強参照カウントまたは弱参照カウントがゼロでない限り、参照カウント構造体は削除されません。

63
James McNellis

少なくとも3つのよく知られたメカニズムがあります。

外部カウンター

オブジェクトへの最初の共有ポインターが作成されると、別の参照カウントオブジェクトが作成され、1に初期化されます。ポインターがコピーされると、参照カウントが増加します。ポインタが破壊されると、ポインタは減少します。ポインタの割り当ては、1つのカウントを増やし、別のカウントを減らします(この順序で、または自己割り当てptr=ptr壊れます)。参照カウントがゼロに達すると、それ以上のポインターは存在せず、オブジェクトは削除されます。

内部カウンター

内部カウンターでは、ポイントされたオブジェクトにカウンターフィールドが必要です。これは通常、特定の基本クラスから派生することによって実現されます。代わりに、これにより参照カウントのヒープ割り当てが節約され、生のポインターから共有ポインターを繰り返し作成できます(外部カウンターを使用すると、1つのオブジェクトに対して2つのカウントになります)

循環リンク

カウンターを使用する代わりに、オブジェクトへのすべての共有ポインターを循環グラフに保持できます。作成された最初のポインタはそれ自体を指します。ポインタをコピーするときは、そのコピーを円に挿入します。削除すると、サークルから削除されます。ただし、破棄されたポインタがそれ自体を指している場合、つまりそれが唯一のポインタである場合は、指し示しているオブジェクトを削除します。

欠点は、循環する単一リンクリストからノードを削除すると、先行ノードを見つけるためにすべてのノードを反復処理する必要があるため、かなりコストがかかることです。これは、参照の局所性が低いために特に苦痛になる可能性があります。

バリエーション

2番目と3番目のアイデアを組み合わせることができます。基本クラスは、カウントを含める代わりに、その円グラフの一部にすることができます。もちろん、これは、オブジェクトがそれ自体を指している場合にのみオブジェクトを削除できることを意味します(サイクル長1、オブジェクトへの残りのポインターはありません)。繰り返しになりますが、弱いポインターからスマートポインターを作成できるという利点がありますが、チェーンからポインターを削除するパフォーマンスの低下は依然として問題です。

アイデア3の正確なグラフ構造はそれほど重要ではありません。また、ルートにポイントされたオブジェクトを使用して、バイナリツリー構造を作成することもできます。繰り返しますが、難しい操作は、そのグラフから共有ポインタノードを削除することです。利点は、多くのスレッドに多くのポインターがある場合、グラフの一部を拡大することは、非常に競合する操作ではないことです。

12
MSalters

これらは、shared_ptrコピーコンストラクター/代入演算子でインクリメントされ、デストラクタでデクリメントされる内部参照カウントを保持します。カウントがゼロになると、保持されているポインタが削除されます。

これがBoostライブラリです ドキュメント スマートポインタ用。 TR1の実装はboost::shared_ptrとほとんど同じだと思います。

0

「共有ポインタは、オブジェクトへのポインタと共有参照カウントへのポインタを保持するスマートポインタ(オーバーロードされた演算子*()と演算子->()を備えたC++オブジェクト)です。スマートポインタのコピーが作成されるたびにコピーコンストラクターを使用すると、参照カウントがインクリメントされます。共有ポインターが破棄されると、そのオブジェクトの参照カウントがデクリメントされます。生のポインターから構築された共有ポインターの参照カウントは、最初は1です。参照カウントが0に達すると、ポイントされます。オブジェクトが破棄され、オブジェクトが占有しているメモリが解放されます。オブジェクトを明示的に破棄する必要はありません。最後のポインタのデストラクタが実行されると自動的に破棄されます。 "From here

0
clyfe