web-dev-qa-db-ja.com

boost、shared_ptr対weak_ptr?いつ使用するのですか?

現在のプロジェクトでは、boost::shared_ptrをかなり広範囲に使用しています。

最近、仲間のチームメイトもweak_ptrを使い始めました。どれをいつ使うかわかりません。

これとは別に、weak_ptrshared_ptrに変換する場合はどうすればよいですか。 weak_ptrをロックしてshared_ptrを作成すると、他のスレッドのコードに影響しますか?

43
RLT

一般的に、要約すると、

強力なポインタ独自の有効性を保証します。たとえば、次のような場合に使用します。

  • 指されているオブジェクトを所有している。あなたはそれを作成して破壊します
  • オブジェクトが存在しない場合は、動作が定義されていません
  • オブジェクトが存在することを強制する必要があります。

弱いポインタ保証知っている独自の有効性。たとえば、次のような場合に使用します。

  • あなたはそれにアクセスしますが、それはあなたのものではありません。
  • オブジェクトが存在しない場合の動作を定義しました

弱いポインターに対するLock()は、強いポインターを返します。これが弱いポインタへのアクセス方法です。オブジェクトが無効になった場合(削除された場合など)、ストロングポインターはNULLになります。それ以外の場合は、オブジェクトをポイントします。これを確認する必要があります。

一時的な(ローカル)強力なポインターを作成し、その強力なポインターが残っている間にオブジェクトの存在を保証したため、使用中に誤ってオブジェクトを削除できないように、このように設定されています。オブジェクトの使用が終了したら、通常、強いポインタをスコープから外す(または再割り当てする)ことで、オブジェクトを削除できるようになります。マルチスレッドの場合は、組み込みのスレッドセーフティを持たない他の処理と同じように扱います。前述の保証willはマルチスレッドの場合にも適用されます。私の知る限り、彼らはそれ以上特別なことは何もしていません。

ブースト共有ポインターには、ガベージコレクターのような機能もあります。これは、オブジェクトへの最後の強力なポインターがなくなるか、別の場所を指すと、オブジェクトが削除されるためです。

他の回答で言及されているパフォーマンスと循環依存関係もあります。

基本的に、boost共有ポインタライブラリを使用すると、プログラムを混乱させることがなくなりますが、ポインタ、オブジェクトの所有権、およびライフタイムを適切に設計するために時間をかけることの代わりにはなりません。そのようなデザインがある場合は、ライブラリを使用してそれを適用できます。そのような設計がない場合、以前とは異なる問題に遭遇する可能性があります。

70
Narfanator

作成するオブジェクトに循環参照が含まれる場合はweak_ptrを使用します。つまり、shared_ptrを使用してオブジェクトにshared_ptrを戻します。これは、shared_ptrが循環参照を処理できないためです。両方のオブジェクトがスコープ外になると、相互参照はそれらのオブジェクトが「ガベージコレクション」されないため、メモリが失われ、メモリリークが発生します。 weak_ptrは参照カウントを増加させないため、循環参照の問題は発生しません。これは、一般に、参照カウントされているものへのポインターを取得するだけで、その参照カウントを増やしたくない場合は、weak_ptrを使用することも意味します。

それ以外の場合は、shared_ptrを使用できます。

詳細については、Boost documentation を確認してください。

23
blwy10

共有ポインターは参照カウントを実装します。弱いポインターは参照カウントに影響しません。オブジェクトへの共有ポインターがない場合は、弱いポインターのみがオブジェクトを削除し、弱いポインターはオブジェクトが失われたことを通知します。

ウィークポインターを使用する理由は2つあります。

  1. 参照カウントの増加/減少のコストを排除するため。ただし、エラーが発生しやすく、時間の節約にもならないため、これを行うべきではありません。
  2. 簿記のデータ構造、例えば「生きている」、つまり別の場所で使用されているすべてのオブジェクトFooのインデックスがあり、すべての「実際の」使用が終了した場合にFooをインデックス内で存続させたくない。これはウィークポインターの基本的な現実的な使用例です。もちろん他にも存在します。

したがって、一般的に、参照先のオブジェクトを削除させてそれを検出したい場合にのみ、弱いポインタを使用することをお勧めします。その他の場合は、共有ポインタ(参照カウント)または直接ポインタを使用します。オブジェクトが削除されないことがわかっている場合は、メソッドローカル変数内。エラーも発生しますが、共有ポインターよりも高速です。

N.B.循環オブジェクトは弱いポインタを必要としません。適切に構築されたプログラムの代わりに、調理されていない通常のポインタを使用できます。ただし、弱いポインタはリスクが低くなります。

6
Antti Huima