使い方とを理解していweak_ptr
ますshared_ptr
。shared_ptr
オブジェクト内の参照の数を数えることで、どのように機能するかを理解しています。どのように機能しweak_ptr
ますか?私はブーストのソースコードを読んでみましたが、ブーストが使用するすべてのものを理解するのに十分な知識がありません。
ありがとう。
使い方とを理解していweak_ptr
ますshared_ptr
。shared_ptr
オブジェクト内の参照の数を数えることで、どのように機能するかを理解しています。どのように機能しweak_ptr
ますか?私はブーストのソースコードを読んでみましたが、ブーストが使用するすべてのものを理解するのに十分な知識がありません。
ありがとう。
shared_ptr
追加の「counter」オブジェクト(別名「sharedcount」または「controlblock」)を使用して、参照カウントを格納します。(BTW:その「counter」オブジェクトはdeleterも格納します。)
すべてshared_ptr
とweak_ptr
には、実際のポインタへのポインタと、「counter」オブジェクトへの2番目のポインタが含まれています。
を実装するためweak_ptr
に、「counter」オブジェクトは2つの異なるカウンターを格納します。
shared_ptr
、オブジェクトを指すインスタンスの数です。weak_ptr
、オブジェクトを指すインスタンスの数に加えて、「使用カウント」がまだ0より大きい場合は1です。「使用回数」がゼロになると、ポインティは削除されます。
「weakcount」がゼロに達すると、「counter」ヘルパーオブジェクトが削除されます(つまり、「use count」もゼロでなければなりません。上記を参照してください)。
shared_ptr
からを取得しようとするとweak_ptr
、ライブラリは「使用回数」をアトミックにチェックし、0より大きい場合はそれをインクリメントします。それが成功した場合、あなたはあなたを取得しますshared_ptr
。「使用回数」がすでにゼロの場合は、shared_ptr
代わりに空のインスタンスを取得します。
編集:では、両方のカウントがゼロに低下したときに「カウンター」オブジェクトを解放するのではなく、なぜ弱いカウントに1を追加するのですか?良い質問。
別の方法は、「使用カウント」と「弱いカウント」の両方がゼロになったときに「カウンター」オブジェクトを削除することです。最初の理由は次のとおりです。すべてのプラットフォームで2つの(ポインターサイズの)カウンターをアトミックにチェックすることは不可能であり、それが存在する場合でも、1つのカウンターだけをチェックするよりも複雑です。
もう1つの理由は、削除機能が実行を終了するまで有効である必要があることです。削除機能は「counter」オブジェクトに格納されているため、「counter」オブジェクトは有効なままである必要があります。shared_ptr
あるオブジェクトに1つ1つ存在weak_ptr
し、それらが並行スレッドで同時にリセットされた場合に何が起こるかを考えてみてください。shared_ptr
が最初に来るとしましょう。「使用回数」をゼロに減らし、削除機能の実行を開始します。ここで、weak_ptr
は「弱いカウント」をゼロに減らし、「使用カウント」もゼロであることがわかります。したがって、「counter」オブジェクトを削除し、それとともに削除者を削除します。削除機能がまだ実行されている間。
もちろん、「counter」オブジェクトが存続することを保証するさまざまな方法がありますが、「weak count」を1つ増やすことは、非常にエレガントで直感的なソリューションだと思います。「weakcount」は「counter」オブジェクトの参照カウントになります。また、shared_ptr
sはカウンタオブジェクトも参照するため、「ウィークカウント」をインクリメントする必要があります。
おそらくさらに直感的な解決策はshared_ptr
、すべてのshared_ptr
ホールドが「カウンター」オブジェクトへの参照であるため、すべてのシングルの「ウィークカウント」をインクリメントすることです。
すべてのインスタンスに1つ追加することshared_ptr
は、単なる最適化です(インスタンスをコピー/割り当てるときに、1つのアトミックインクリメント/デクリメントを節約しshared_ptr
ます)。
基本的に、「weak_ptr」は通常の「T *」ポインタであり、コードの後半で強力な参照、つまり「shared_ptr」を回復できます。
通常のT*と同様に、weak_ptrは参照カウントを行いません。内部的には、任意の型Tでの参照カウントをサポートするために、STL(またはこの種のロジックを実装する他のライブラリ)は、「アンカー」と呼ばれるラッパーオブジェクトを作成します。「アンカー」は、参照カウントを実装するためだけに存在し、「カウントがゼロの場合は、削除を呼び出す」動作が必要です。
強力な参照では、shared_ptrは、そのコピー、operator =、コンストラクタ、デストラクタ、およびその他の関連するAPIを実装して、「Anchor」の参照カウントを更新します。これは、shared_ptrが、誰かがそれを使用している限り、あなたの「T」が正確に存続することを保証する方法です。「weak_ptr」では、これらの同じAPIが実際のアンカーptrをコピーするだけです。参照カウントは更新されません。
これが、「weak_ptr」の最も重要なAPIが「期限切れ」であり、名前が不適切な「ロック」である理由です。「期限切れ」は、基になるオブジェクトがまだ存在するかどうかを示します。つまり、「すべての強力な参照がスコープ外になったため、オブジェクトはすでに削除されていますか?」「ロック」は(可能な場合)weak_ptrを強力な参照shared_ptrに変換し、参照カウントを復元します。
ところで、「ロック」はそのAPIのひどい名前です。あなたは(ただ)ミューテックスを呼び出しているのではなく、弱いものから強いリファレンスを作成していて、その「アンカー」が機能しています。両方のテンプレートの最大の欠点は、演算子->が実装されていないことです。そのため、オブジェクトで何かを行うには、生の「T*」を復元する必要があります。プリミティブ型は「->」演算子をサポートしていないため、主に「shared_ptr」などをサポートするためにこれを行いました。