299

重複の可能性:
pimpl: shared_ptr または unique_ptr
スマート ポインター (ブースト) の説明

誰かが shared_ptr と unique_ptr の違いを説明できますか?

4

4 に答える 4

599

これらのクラスは両方ともスマート ポインターです。つまり、オブジェクトが参照できなくなると、それらは (ほとんどの場合) 自動的に、それらが指しているオブジェクトの割り当てを解除します。2 つの違いは、リソースを参照できる各タイプの異なるポインターの数です。

を使用する場合、任意の 1 つのリソースを指すのはunique_ptr最大 1つです。unique_ptrそれunique_ptrが破棄されると、リソースは自動的に回収されます。unique_ptrどのリソースにも1 つしか存在できないため、 のコピーを作成しようとするunique_ptrと、コンパイル時エラーが発生します。たとえば、次のコードは違法です。

unique_ptr<T> myPtr(new T);       // Okay
unique_ptr<T> myOtherPtr = myPtr; // Error: Can't copy unique_ptr

ただし、新しい移動セマンティクスを使用して移動unique_ptrできます。

unique_ptr<T> myPtr(new T);                  // Okay
unique_ptr<T> myOtherPtr = std::move(myPtr); // Okay, resource now stored in myOtherPtr

同様に、次のようなこともできます。

unique_ptr<T> MyFunction() {
    unique_ptr<T> myPtr(/* ... */);

    /* ... */

    return myPtr;
}

このイディオムは、「私は管理対象リソースをあなたに返します。戻り値を明示的に取得しない場合、リソースはクリーンアップされます。取得した場合、そのリソースの排他的所有権を取得したことになります。」を意味します。unique_ptrこのように、 のより安全で優れた代替品と考えることができますauto_ptr

shared_ptr一方、複数のポインターが特定のリソースを指すことができます。リソースの最後のshared_ptrものが破棄されると、リソースの割り当てが解除されます。たとえば、次のコードは完全に合法です。

shared_ptr<T> myPtr(new T);       // Okay
shared_ptr<T> myOtherPtr = myPtr; // Sure!  Now have two pointers to the resource.

内部的には、参照カウントshared_ptrを使用してリソースを参照するポインターの数を追跡するため、参照サイクルを導入しないように注意する必要があります。

要するに:

  1. unique_ptr単一のポインターが破棄されたときに再利用されるオブジェクトへの単一のポインターが必要な場合に使用します。
  2. shared_ptr同じリソースへの複数のポインターが必要な場合に使用します。

お役に立てれば!

于 2011-07-29T17:32:39.457 に答える
88

unique_ptr1人の消費者が唯一の(したがって「一意の」)責任を負う動的オブジェクトがどこかにある場合、軽量のスマートポインターが選択されます-おそらく、動的に割り当てられたオブジェクトを維持する必要があるラッパークラスです。unique_ptrオーバーヘッドはほとんどありません。コピー可能ではありませんが、移動可能です。そのはであるため、 2 つのテンプレート パラメータtemplate <typename D, typename Deleter> class unique_ptr;に依存します。

unique_ptrまたauto_ptr、古い C++ に入れたかったのですが、その言語の制限のためにできませんでした。

shared_ptr一方、非常に異なる動物です。明らかな違いは、多くのコンシューマーが動的オブジェクトの責任を共有できること (つまり「共有」) であり、すべての共有ポインターがなくなったときにのみオブジェクトが破棄されることです。さらに、フォローしている共有ポインターが消えた場合にインテリジェントに通知される弱いポインターを監視することができます。

内部的にshared_ptrは、さらに多くの処理が行われています: 同時実行コードで使用できるようにアトミックに更新される参照カウントがあります。また、多くの割り当てが行われています。1 つは内部簿記の「参照制御ブロック」用で、もう 1 つは (多くの場合) 実際のメンバー オブジェクト用です。

しかし、もう 1 つの大きな違いがあります。共有ポインターの型は常にです。これは、カスタムのデリータ template <typename T> class shared_ptr;カスタムのアロケータを使用して初期化できるという事実にもかかわらずです。デリータとアロケータは、型の消去と仮想関数のディスパッチを使用して追跡されます。これにより、クラスの内部的な重みが増しますが、削除と割り当ての詳細に関係なく、さまざまな種類の型の共有ポインタがすべて互換性があるという大きな利点があります。したがって、消費者に詳細な負担をかけることなく、「責任の共有」の概念を真に表現しています。TT

shared_ptrとはどちらも、unique_ptr値渡しされるように設計されています (一意のポインターに対する明らかな移動可能性要件があります)。それらのパワーは本当に驚異的であるため、どちらもオーバーヘッドを心配する必要はありませんが、選択肢がある場合は、 を優先し、本当に共有責任が必要な場合unique_ptrにのみ使用してください。shared_ptr

于 2011-07-29T17:36:50.033 に答える
21

unique_ptr
は、オブジェクトを排他的に所有するスマート ポインターです。

shared_ptr
は共有所有権のスマート ポインターです。copyableとの両方movableです。複数のスマート ポインター インスタンスが同じリソースを所有できます。リソースを所有する最後のスマート ポインターが範囲外になるとすぐに、リソースは解放されます。

于 2011-07-29T17:32:02.673 に答える
11

でポインタをラップする場合、 のunique_ptr複数のコピーを持つことはできませんunique_ptr。はshared_ptr、格納されたポインターのコピーの数をカウントする参照カウンターを保持します。shared_ptraがコピーされるたびに、このカウンターがインクリメントされます。shared_ptraが破壊されるたびに、このカウンターはデクリメントされます。このカウンタが 0 になると、格納されたオブジェクトは破棄されます。

于 2011-07-29T17:31:38.080 に答える