回答:
各スマートポインターを割り当てることができるプロパティがある場合は簡単です。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のmoveコンストラクターを使用して移動できます。
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をベクトルに詰め込むことができます。これについて詳しく知りたい場合は、ここで停止し、これに関する良い記事を紹介します。
auto_ptr
はすでに非推奨です(C ++ 11)。
intrusive_ptr
せるshared_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がある場合に使用されます。参照カウントを追加およびデクリメントする無料の関数を呼び出します。詳細については、ドキュメントを強化するためのリンクを参照してください。
if (tPtrAccessed[0].get() == 0)
と思いませんif (tPtrAccessed.get() == 0)
か?
boost::ptr_container
ブーストスマートポインターの調査で見落とさないでください。たとえば、eg std::vector<boost::shared_ptr<T> >
が遅すぎるような状況では、これらは非常に貴重です。
ドキュメンテーションを見ることに関するアドバイスの2番目です。見た目ほど怖くないです。そしていくつかの短いヒント:
scoped_ptr
-範囲外になると、ポインターは自動的に削除されます。注-割り当てはできませんが、オーバーヘッドは発生しませんintrusive_ptr
-のオーバーヘッドのない参照カウントポインターsmart_ptr
。ただし、オブジェクト自体は参照カウントを格納しますweak_ptr
-と一緒に動作します shared_ptr
循環依存が発生する状況に対処します(ドキュメントを読んで、グーグルで素敵な画像を検索してください;)shared_ptr
-(boostによって提供されるものからの)スマートポインターの一般的で最も強力な(そしてヘビー級の)auto_ptr
、コントロールがスコープを離れると、ポイントするオブジェクトが自動的に破棄されることを保証するoldもあります。ただし、他の人とはコピーのセマンティクスが異なります。unique_ptr
- C ++ 0xで来ます編集への応答: はい