web-dev-qa-db-ja.com

unique_ptrとshared_ptrの違い

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

Shared_ptrとunique_ptrの違いを説明できますか。

200
smallB

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

unique_ptrを使用するとき、最大1つのunique_ptrが任意の1つのリソースを指すことができます。その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_ptrauto_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を使用してください。

お役に立てれば!

434
templatetypedef

unique_ptrは、どこかに動的オブジェクトがある場合に最適な軽量のスマートポインタです。one消費者は唯一の(したがって "ユニークな")責任を持ちます - おそらく動的にいくつかを維持する必要があるラッパークラスです。割り当てられたオブジェクトunique_ptrはほとんどオーバーヘッドがありません。コピー可能ではありませんが、移動可能です。そのtypetemplate <typename D, typename Deleter> class unique_ptr;なので、twoテンプレートパラメータに依存します。

unique_ptrは、auto_ptrが古いC++に含まれることを望んでいたものでもありますが、その言語の制限のためにできませんでした。

一方shared_ptrは非常に異なる動物です。明らかな違いは、動的なオブジェクトに対する責任を共有する多くのコンシューマ(したがって「共有」)を持つことができ、そのオブジェクトはすべての共有ポインタがなくなったときにのみ破棄されるということです。加えて、あなたは観察しているweak pointersこれは彼らがフォローしている共有ポインタが消えたかどうかをインテリジェントに知らされるでしょう。

内部的には、shared_ptrにはもっと多くのことがあります。参照カウントがあります。これは、並行コードでの使用を可能にするためにアトミックに更新されます。また、たくさんの割り当てが行われています。1つは内部簿記の「参照制御ブロック」用で、もう1つは(多くの場合)実際のメンバーオブジェクト用です。

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

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

69
Kerrek SB

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

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

17
Alok Save

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

8
neodelphi