c++ - 使い方 - unique_ptr<>




スマートポインタ:またはあなたの赤ちゃんを所有している人は? (8)

C ++はすべてメモリ所有権に関するものです
別名「 オーナーシップセマンティクス

そのメモリを解放するのは、動的に割り当てられたメモリのチャンクの所有者の責任です。 だから問題は本当に誰が記憶を所有するのかになります。

C ++の所有権は、RAWポインタがラップされているタイプ(RAWポインタには推論されていない所有権がないため、非常にまれです)[RAW NOT NEVER]誰がメモリを所有しているかを知ることができます。したがって、誰がオーナーシップを担当しているかわからないドキュメントを慎重に読まなくてもかまいません。

逆に、各RAWポインタがそれ自身のSMARTポインタラッパー内に格納されているクラスに格納されているRAWポインタを見ることはまれです。 ( 注:オブジェクトを所有していない場合は、オブジェクトがスコープから外れて破棄されることがわからないため、オブジェクトを格納してはいけません。)

だから質問:

  • どのようなタイプの所有権セマンティックが人々に出会うのですか?
  • これらのセマンティクスを実装するために使用される標準クラスは何ですか?
  • どのような状況でそれらが有用であると思いますか?

1つの回答につき1種類の意味所有権を保持し、個別に投票できるようにします

概要:

概念的にスマートポインタはシンプルであり、簡単な実装は簡単です。 私は多くの試みが試されているのを見たことがありますが、どういうわけか、彼らは何らかの方法で壊れています。 したがって、私はいつもあなたのものを動かすのではなく、ライブラリからうまくテストされた "スマートポインタ"を使うことを勧めます。 std :: auto_ptrまたはブーストスマートポインタの1つが私の必要をすべてカバーしているようです。

std :: auto_ptr <T>:

一人の人間がオブジェクトを所有しています。
しかし、所有権の移転は許されます。

使用法:
======
これにより、所有権の明示的な転送を示すインターフェイスを定義することができます。

boost :: scoped_ptr <T>

一人の人間がオブジェクトを所有しています。
所有権の移転は認められません。

使用法:
======
明示的な所有権の表示に使用されます。
オブジェクトはデストラクタによって、または明示的にリセットされると破棄されます。

boost :: shared_ptr <T>(std :: tr1 :: shared_ptr <T>)

複数の所有権。
これは単純な参照カウントポインタです。 参照カウントがゼロになると、オブジェクトは破棄されます。

使用法:
======
オブジェクトがコンパイル時に決定できない寿命を持つ複数のowerを持つことができるとき。

boost :: weak_ptr <T>

shared_ptr <T>とともに使用されます。
ポインタのサイクルが発生する場合があります。

使用法:
======
サイクルのみが共有参照カウントを維持しているときに、オブジェクトの保持からサイクルを停止するために使用されます。


シンプルなC ++モデル

私が見たほとんどのモジュールでは、デフォルトでは、ポインタを受け取っても所有権が得られいないとみなされていました。 実際に、ポインタの所有権を放棄する関数/メソッドは非常にまれであり、そのドキュメントでその事実を明示的に表現していました。

このモデルでは、ユーザーが明示的に割り当てたものの所有者であることが前提です 。 それ以外のものは自動的に(スコープ出口またはRAII経由で)処分されます。 これはCのようなモデルで、ほとんどのポインタは自動的にまたは必要に応じて(オブジェクトの破棄で)割り当てを解除するオブジェクトによって所有され、オブジェクトの存続期間は予測可能です(RAIIはあなたの友人であり、再び)。

このモデルでは、生ポインタは自由に循環し、ほとんど危険ではありません(ただし、開発者が十分にスマートであれば、可能な限り参照を使用します)。

  • 生ポインタ
  • std :: auto_ptr
  • boost :: scoped_ptr

Smart Pointed C ++モデル

スマートポインタでいっぱいのコードでは、ユーザーはオブジェクトの存続期間を無視することができます。 所有者は決してユーザーコードではありません。それはスマートポインタそのものです(RAII、もう一度)。 問題は、参照カウントされたスマートポインタと混在した循環参照が致命的になる可能性があるため、共有ポインタと弱ポインタ​​の両方を処理する必要があることです。 だからあなたはまだ所有権を考慮しなければなりません(弱ポインタ​​は、たとえ未処理ポインタよりも利点があっても何も指し示すことができません)。

  • boost :: shared_ptr
  • boost :: weak_ptr

結論

私が記述しているモデルに関係なく、例外を除いてポインタを受け取っても所有権が得られず 、誰が所有しているのかを知ることは非常に重要です 。 参照やスマートポインタを頻繁に使用するC ++コードの場合でも。


boostから、 ポインタコンテナライブラリもあります 。 これらは、コンテナのコンテキストでのみオブジェクトを使用している場合は、スマートポインタの標準コンテナよりも少し効率的で使いやすくなります。

Windowsでは、COMポインタ(IUnknown、IDispatch、およびfriends)、およびそれらを処理するためのさまざまなスマートポインタがあります(たとえば、 _com_ptrクラスに基づいてVisual Studioの "import"ステートメントによって自動生成されるATLのCComPtrおよびスマートポインタ)。


std::tr1::shared_ptr<Blah>はしばしばあなたの最良の賭けです。


共有所有権を持っていない。 そうしている場合は、制御していないコードだけであることを確認してください。

これは100%の問題を解決します。なぜなら、すべてのものがどのように相互作用するのかを理解することが必要になるからです。


私は自分のデザインに所有権を共有する立場にいるとは思わない。 実際、私の頭の上から、私が考えることができる唯一の有効なケースはFlyweightパターンです。


頻繁に使用される単一転送可能所有者の別の形式があり、 auto_ptrの代入セマンティクスの狂った破損によって引き起こされる問題を回避できるので、 auto_ptrよりも好ましい。

私はswap以外の話はしません。 適切なswap機能を持つ任意のタイプは、オーナーシップが同じタイプの別のインスタンスに転送されるまでswapすることによって所有する一部のコンテンツへのスマートな参照として考えることができます。 各インスタンスは同一性を保持しますが、新しいコンテンツにバインドされます。 これは、安全に再結合可能な参照のようなものです。

(スマートポインタではなく、スマートな参照であるため、コンテンツを取得するために明示的に逆参照する必要はありません)。

これは、auto_ptrの必要性が減り、タイプが適切なswap機能を持たないギャップを埋める必要があることを意味します。 しかし、すべての標準コンテナがあります。


  • ワンオーナー
  • boost :: scoped_ptr

メモリを動的に割り当てる必要があるときに、ブロックのすべての出口ポイントでメモリが割り当て解除されていることを確認したいとき。

私は簡単に再シールすることができ、漏れを気にすることなく解放できるので、これは便利です


  • 共有所有権
  • boost :: shared_ptr

リソースが複数のオブジェクト間で共有される場合。 ブーストshared_ptrは、参照カウントを使用して、誰もがフィンイングされたときにリソースが割り当て解除されることを確認します。





ownership-semantics