次の一連のポインターの違いは何ですか? 本番コードで各ポインターを使用する場合、いつ使用しますか?
例をいただければ幸いです。
scoped_ptr
shared_ptr
weak_ptr
intrusive_ptr
プロダクションコードでブーストを使用していますか?
次の一連のポインターの違いは何ですか? 本番コードで各ポインターを使用する場合、いつ使用しますか?
例をいただければ幸いです。
scoped_ptr
shared_ptr
weak_ptr
intrusive_ptr
プロダクションコードでブーストを使用していますか?
各スマート ポインターに割り当てることができるプロパティがあれば簡単です。3 つの重要なプロパティがあります。
1 つ目は、スマート ポインターはオブジェクトを所有していないため、オブジェクトを削除できないことを意味します。2 つ目は、同時に同じオブジェクトを指すことができるスマート ポインターは 1 つだけであることを意味します。たとえば、スマート ポインターが関数から返される場合、所有権は返されたスマート ポインターに転送されます。
3 つ目は、複数のスマート ポインターが同時に同じオブジェクトを指すことができることを意味します。これは生のポインターにも当てはまりますが、生のポインターには重要な機能がありません。所有しているかどうかを定義しません。すべての所有者がオブジェクトを放棄した場合、所有権の共有スマート ポインターはオブジェクトを削除します。この動作はたまたま頻繁に必要になるため、共有所有スマート ポインターは広く普及しています。
一部の所有スマート ポインターは、2 番目も 3 番目もサポートしません。したがって、関数から返すことも、他の場所に渡すこともできません。RAII
これは、スマート ポインターがローカルに保持され、作成されたばかりであるため、オブジェクトがスコープ外になった後にオブジェクトを解放する目的に最も適しています。
所有権の共有は、コピー コンストラクターを持つことで実装できます。これは自然にスマート ポインターをコピーし、コピーとオリジナルの両方が同じオブジェクトを参照します。現在、C++ では所有権の譲渡を実際に実装することはできません。これは、あるオブジェクトから別のオブジェクトに何かを譲渡する手段が言語でサポートされていないためです。関数からオブジェクトを返そうとすると、オブジェクトがコピーされます。そのため、所有権の譲渡を実装するスマート ポインターは、コピー コンストラクターを使用して所有権の譲渡を実装する必要があります。ただし、これはコンテナでの使用を妨げます。これは、これらのスマート ポインタのいわゆる「移動コンストラクタ」動作と互換性のない、コンテナの要素のコピー コンストラクタの特定の動作が要件で規定されているためです。
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 は、次の C++ 標準リリースで非推奨になり、unique_ptr が優先されます。C++1x では、移動のみ可能でコンテナーにコピーできないオブジェクトのスタッフィングも許可されます。したがって、たとえば、unique_ptr をベクターに詰め込むことができます。これについて詳しく知りたい場合は、ここで終了し、これに関する優れた記事を参照してください。
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 がある場合に使用されます。無料の関数を呼び出して、参照カウントを追加および減少させます。詳細については、Boost のドキュメントへのリンクを参照してください。
boost::ptr_container
ブーストスマートポインターの調査で見落とさないでください. std::vector<boost::shared_ptr<T> >
それらは、egが遅すぎる状況で非常に貴重な場合があります。
ドキュメントを見ることについてのアドバイスを2番目にします。見た目ほど怖くないです。そしていくつかの短いヒント:
scoped_ptr
- 範囲外になると自動的に削除されるポインター。注 - 代入はできませんが、オーバーヘッドは発生しませんintrusive_ptr
- のオーバーヘッドのない参照カウント ポインターsmart_ptr
。ただし、オブジェクト自体が参照カウントを格納しますweak_ptr
- と連携してshared_ptr
、循環依存関係が発生する状況に対処します (ドキュメントを読み、Google で素敵な画像を検索してください ;)shared_ptr
- 一般的で最も強力な (そして重量のある) スマート ポインター (boost によって提供されるものから)auto_ptr
コントロールがスコープを離れたときに、それが指すオブジェクトが自動的に破棄されることを保証するold もあります。ただし、コピーのセマンティクスは他のものとは異なります。unique_ptr
- C++0x が付属します編集への対応: はい