121

C++ はメモリの所有権、つまり所有権のセマンティクスがすべてです。

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

C++ では、所有権は生のポインターが内部でラップされる型によって文書化されているため、優れた (IMO) C++ プログラムでは、生のポインターが渡されるのを見ることは非常にまれです (まれではありませ)。誰がメモリを所有しているのかわからないため、ドキュメントを注意深く読まなければ、誰が所有権を持っているのかわかりません)。

逆に、生のポインターがクラスに格納されることはほとんどありません。各生のポインターは、独自のスマート ポインター ラッパー内に格納されます。(注:オブジェクトを所有していない場合は、オブジェクトを保存するべきではありません。オブジェクトがいつスコープから外れて破棄されるかがわからないためです。)

だから質問:

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

回答ごとに 1 種類のセマンティック オーナーシップを保持して、個別に投票できるようにします。

概要:

概念的には、スマート ポインターは単純であり、単純な実装は簡単です。私は多くの試みられた実装を見てきましたが、それらは常に何らかの方法で壊れており、カジュアルな使用や例では明らかではありません. したがって、独自のスマート ポインターを展開するのではなく、ライブラリから十分にテストされたスマート ポインターを常に使用することをお勧めします。std::auto_ptrまたは、Boost スマート ポインターの 1 つが私のニーズをすべてカバーしているようです。

std::auto_ptr<T>:

1 人の人物がオブジェクトを所有しています。所有権の譲渡は許可されています。

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

boost::scoped_ptr<T>

1 人の人物がオブジェクトを所有しています。所有権の譲渡は許可されていません。

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

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

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

使用法: オブジェクトが、コンパイル時に決定できない有効期間を持つ複数の権限を持つことができる場合。

boost::weak_ptr<T>:

shared_ptr<T>ポインターのサイクルが発生する可能性がある状況で使用されます。

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

4

11 に答える 11

24

シンプルな C++ モデル

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

このモデルは、ユーザーが明示的に割り当てたもののみの所有者であると想定しています。それ以外はすべて自動的に破棄されます (スコープの終了時、または RAII を介して)。これは C に似たモデルであり、ほとんどのポインターがオブジェクトによって所有され、自動的に、または必要に応じて (ほとんどの場合、オブジェクトの破棄時に) 割り当てを解除し、オブジェクトの寿命が予測可能である (RAII はあなたの友人です。また)。

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

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

スマート ポイント C++ モデル

スマート ポインターでいっぱいのコードでは、ユーザーはオブジェクトの有効期間を無視することを期待できます。所有者は決してユーザー コードではありません。それはスマート ポインターそのものです (再び RAII)。問題は、参照カウントのスマート ポインターと循環参照が混在すると危険な場合があるため、共有ポインターと弱いポインターの両方を処理する必要があることです。したがって、考慮すべき所有権はまだあります (弱いポインターは、生のポインターに対する利点がそうであることを示すことができるとしても、何も指さない可能性があります)。

  • ブースト::shared_ptr
  • boost::weak_ptr

結論

私が説明するモデルに関係なく、例外を除いて、ポインターを受け取ることはその所有権を受け取ることではなく、誰が誰を所有しているかを知ることは依然として非常に重要です。参照やスマート ポインターを多用する C++ コードの場合でも。

于 2008-09-18T19:39:20.933 に答える
21

私にとって、これらの 3 種類が私のニーズのほとんどをカバーしています。

shared_ptr- カウンターがゼロに達したときの参照カウント、解放

weak_ptr- 上記と同じですが、これは a の「スレーブ」でありshared_ptr、割り当てを解除できません

auto_ptr- 作成と割り当て解除が同じ関数内で発生する場合、またはオブジェクトが 1 人の所有者のみと見なされる必要がある場合。あるポインターを別のポインターに割り当てると、2 番目のポインターが最初のポインターからオブジェクトを「盗み」ます。

これらの独自の実装がありますが、.NETでも利用できますBoost

私はまだ参照によってオブジェクトを渡します (const可能な限り)。この場合、呼び出されたメソッドは、呼び出し時にのみオブジェクトが生きていると想定する必要があります。

私が使用する別の種類のポインターがあり、これをhub_ptrと呼びます。ネストされたオブジェクトから (通常は仮想基本クラスとして) アクセス可能でなければならないオブジェクトがある場合です。これは、それらに a を渡すことで解決できますが、それ自体weak_ptrには to がありませんshared_ptr。これらのオブジェクトが彼より長く生きないことを知っているので、hub_ptr をそれらに渡します (これは、通常のポインターへのテンプレート ラッパーにすぎません)。

于 2008-09-18T17:07:05.887 に答える
10

所有権を共有しないでください。そうした場合は、自分が管理していないコードだけを使用していることを確認してください。

すべてがどのように相互作用するかを理解する必要があるため、問題は100%解決されます。

于 2008-09-18T17:27:44.370 に答える
2
  • 共有所有権
  • ブースト::shared_ptr

リソースが複数のオブジェクト間で共有される場合。ブースト shared_ptr は参照カウントを使用して、全員が終了したときにリソースの割り当てが解除されるようにします。

于 2008-09-18T16:37:35.707 に答える
2

std::tr1::shared_ptr<Blah>多くの場合、最善の策です。

于 2008-09-18T16:38:51.227 に答える
2

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

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

于 2008-12-21T12:13:33.663 に答える
1

single-transferable-owner の別の頻繁に使用される形式があり、割り当てセマンティクスの非常識な破損auto_ptrによって引き起こされる問題を回避するため、それが望ましいです。auto_ptr

私は他ならぬことを話しswapます。適切な機能を備えたタイプは、コンテンツへのスマートな参照swapと考えることができます。これは、所有権が同じタイプの別のインスタンスに交換されるまで所有されます。各インスタンスはその ID を保持しますが、新しいコンテンツにバインドされます。安全に再バインド可能な参照のようなものです。

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

swapこれは、auto_ptr の必要性が低くなることを意味します。タイプが適切な機能を持たないギャップを埋めるためにのみ必要です。しかし、すべての std コンテナーはそうします。

于 2008-12-21T12:29:49.417 に答える
1

yasper::ptr は軽量で、boost::shared_ptr のような代替手段です。私の(今のところ)小さなプロジェクトではうまくいきます。

http://yasper.sourceforge.net/の Web ページでは、次のように説明されています。

別の C++ スマート ポインターを作成する理由 C++ 用の高品質なスマート ポインターの実装が既にいくつか存在します。最も顕著なのは、Boost ポインター パンテオンと Loki の SmartPtr です。スマート ポインターの実装の適切な比較と、それらの使用が適切な場合については、Herb Sutter の The New C++: Smart(er) Pointers をお読みください。他のライブラリの拡張機能とは対照的に、Yasper は参照カウント ポインタに限定されています。これは、Boost の shared_ptr および Loki の RefCounted/AllowConversion ポリシーと密接に対応しています。Yasper を使用すると、C++ プログラマーは、Boost の大きな依存関係を導入したり、Loki の複雑なポリシー テンプレートについて学習したりすることなく、メモリ管理を忘れることができます。哲学

* small (contained in single header)
* simple (nothing fancy in the code, easy to understand)
* maximum compatibility (drop in replacement for dumb pointers)

yasper は、他の実装では許可されていない危険な (しかし有用な) アクション (生のポインターへの代入や手動解放など) を許可するため、最後の点は危険な場合があります。注意してください。これらの機能は、自分が何をしているのかわかっている場合にのみ使用してください!

于 2008-12-21T05:18:48.960 に答える
1
  • ワンオーナー
  • boost::scoped_ptr

メモリを動的に割り当てる必要があるが、ブロックのすべての終了ポイントで確実に割り当てを解除したい場合。

簡単に取り付け直して、漏れを心配することなく解放できるので、これは便利だと思います

于 2008-09-18T17:04:08.763 に答える
1

自分のデザインの所有権を共有できる立場にあったことはないと思います。実際、頭の中で考えられる唯一の有効なケースは Flyweight パターンです。

于 2008-09-18T17:13:47.570 に答える
0
  • 1 人の所有者: コピー時に削除
  • std::auto_ptr

オブジェクトの作成者が明示的に所有権を他の誰かに渡したい場合。これは、私がこれを提供しているコードに文書化する方法でもあります。私はもう追跡していないので、終了したら必ず削除してください。

于 2008-09-18T16:35:24.293 に答える