web-dev-qa-db-ja.com

スマートポインター(ブースト)の説明

次の一連のポインターの違いは何ですか?本番コードで各ポインターを使用するのはいつですか?

例に感謝します!

  1. scoped_ptr

  2. shared_ptr

  3. weak_ptr

  4. intrusive_ptr

製品コードでブーストを使用しますか?

214
Sasha

スマートポインターの基本プロパティ

各スマートポインターを割り当てることができるプロパティがある場合は簡単です。 3つの重要なプロパティがあります。

  • 所有権がまったくない
  • 所有権の移転
  • 所有権のシェア

1つ目は、スマートポインターがオブジェクトを所有していないため、オブジェクトを削除できないことを意味します。 2番目は、1つのスマートポインターのみが同じオブジェクトを同時に指すことができることを意味します。スマートポインターが関数から返される場合、たとえば、所有権は返されたスマートポインターに転送されます。

3番目は、複数のスマートポインターが同じオブジェクトを同時に指すことができることを意味します。これはrawポインターにも適用されますが、rawポインターには重要な機能がありません。owningであるかどうかを定義しません。すべての所有者がオブジェクトを放棄した場合、所有権の共有スマートポインターはオブジェクトを削除します。この動作は頻繁に必要になるため、共有所有のスマートポインターが広く普及しています。

一部の所有スマートポインターは、2番目も3番目もサポートしません。したがって、関数から返されたり、他の場所に渡されることはありません。これは、スマートポインターがローカルに保持され、オブジェクトがスコープ外に出た後にオブジェクトを解放するように作成されるというRAIIの目的に最も適しています。

所有権の共有は、コピーコンストラクターを使用して実装できます。これにより、自然にスマートポインターがコピーされ、コピーとオリジナルの両方が同じオブジェクトを参照します。所有権の移転は、現在C++で実際に実装することはできません。1つのオブジェクトから言語でサポートされる別のオブジェクトに何かを移転する手段がないためです。関数からオブジェクトを返そうとすると、オブジェクトがコピーされます。したがって、所有権の移転を実装するスマートポインターは、コピーコンストラクターを使用して所有権の移転を実装する必要があります。ただし、コンテナの要素のコピーコンストラクターの特定の動作は、これらのスマートポインターのいわゆる「移動コンストラクター」動作と互換性がないため、コンテナーでの使用が中断されます。

C++ 1xは、いわゆる「コンストラクターの移動」と「代入演算子の移動」を導入することで、所有権の譲渡をネイティブにサポートします。また、unique_ptrと呼ばれる所有権の譲渡スマートポインターも付属しています。

スマートポインターの分類

scoped_ptrは、転送も共有もできないスマートポインターです。ローカルでメモリを割り当てる必要がある場合に使用できますが、スコープ外になった場合は必ず解放してください。ただし、必要に応じて、別のscoped_ptrと交換できます。

shared_ptrは、所有権を共有するスマートポインターです(上記の3番目の種類)。参照カウントであるため、その最後のコピーがスコープ外になり、管理対象オブジェクトを解放するタイミングを確認できます。

weak_ptrは非所有のスマートポインターです。参照カウントを追加せずに(shared_ptrによって管理される)管理対象オブジェクトを参照するために使用されます。通常、shared_ptrから生のポインタを取得し、それをコピーする必要があります。しかし、オブジェクトが実際に削除されたことを確認する方法がないため、これは安全ではありません。したがって、weak_ptrは、shared_ptrによって管理されるオブジェクトを参照することで手段を提供します。オブジェクトにアクセスする必要がある場合、オブジェクトの管理をロックして(別のスレッドでshared_ptrがオブジェクトの使用中に解放することを避けるため)、それを使用できます。 weak_ptrがすでに削除されたオブジェクトを指している場合、例外をスローして通知します。 weak_ptrの使用は、循環参照がある場合に最も有益です。参照カウントは、このような状況に簡単に対処できません。

intrusive_ptrはshared_ptrに似ていますが、参照カウントをshared_ptrに保持せず、管理対象のオブジェクトで定義する必要のあるヘルパー関数のカウントをインクリメント/デクリメントします。これには、すでに参照されているオブジェクト(外部参照カウントメカニズムによって参照カウントがインクリメントされる)をintrusive_ptrに詰め込むことができるという利点があります。参照カウントはスマートポインターの内部ではなく、スマートポインターが既存の参照カウント機構。

unique_ptrは、所有権の譲渡ポインターです。コピーすることはできませんが、C++ 1xの移動コンストラクターを使用して移動できます。

unique_ptr<type> p(new type);
unique_ptr<type> q(p); // not legal!
unique_ptr<type> r(move(p)); // legal. p is now empty, but r owns the object
unique_ptr<type> s(function_returning_a_unique_ptr()); // legal!

これはstd :: auto_ptrが従うセマンティックですが、移動に対するネイティブサポートが欠落しているため、落とし穴なしで提供することはできません。 unique_ptrは、移動セマンティクスの主要な機能の1つである一時的な他のunique_ptrからリソースを自動的に盗みます。 auto_ptrは、unique_ptrを支持して、次のC++標準リリースで非推奨になります。 C++ 1xでは、コンテナにコピーすることはできず、移動のみが可能なオブジェクトを詰めることもできます。したがって、unique_ptrをベクトルに詰め込むことができます。これについてもっと詳しく知りたい場合は、ここで立ち止まって、 すばらしい記事 を参照してください。

334

scoped_ptrが最も簡単です。範囲外になると破棄されます。次のコードは違法です(scoped_ptrsはコピー不可)が、ポイントを説明します:

std::vector< scoped_ptr<T> > tPtrVec;
{
     scoped_ptr<T> tPtr(new T());
     tPtrVec.Push_back(tPtr);
     // raw T* is freed
}
tPtrVec[0]->DoSomething(); // accessing freed memory

shared_ptrは参照カウントです。コピーまたは割り当てが発生するたびに、参照カウントがインクリメントされます。インスタンスのデストラクタが起動されるたびに、生のT *の参照カウントが減ります。 0になると、ポインターは解放されます。

std::vector< shared_ptr<T> > tPtrVec;
{
     shared_ptr<T> tPtr(new T());
     // This copy to tPtrVec.Push_back and ultimately to the vector storage
     // causes the reference count to go from 1->2
     tPtrVec.Push_back(tPtr);
     // num references to T goes from 2->1 on the destruction of tPtr
}
tPtrVec[0]->DoSomething(); // raw T* still exists, so this is safe

weak_ptrは、共有ポインタへの弱参照であり、ポイント先のshared_ptrがまだ存在するかどうかを確認する必要があります

std::vector< weak_ptr<T> > tPtrVec;
{
     shared_ptr<T> tPtr(new T());
     tPtrVec.Push_back(tPtr);
     // num references to T goes from 1->0
}
shared_ptr<T> tPtrAccessed =  tPtrVec[0].lock();
if (tPtrAccessed[0].get() == 0)
{
     cout << "Raw T* was freed, can't access it"
}
else
{
     tPtrVec[0]->DoSomething(); // raw 
}

intrusive_ptrは通常、使用する必要があるサードパーティのスマートptrがある場合に使用されます。無料の関数を呼び出して、参照カウントを追加および減分します。詳細については、ドキュメントを後押しするには link を参照してください。

90
Doug T.

ブーストスマートポインターの調査では、 boost::ptr_container を見落とさないでください。それらは、例えばstd::vector<boost::shared_ptr<T> >が遅すぎる場合に非常に貴重です。

20
timday

次に、ドキュメントを参照することについてのアドバイスをします。見た目ほど怖くない。そして、いくつかの短いヒント:

編集する応答:はい

12
Anonymous