すべての質問に対する答えは、最終的には同じになります。参照セマンティクスと値セマンティクスのどちらが必要かによって異なります(いくつかの注意点を考慮に入れる必要があります)。
キーワードで宣言されたUDT(ユーザー定義データ型)のJavaやC#などの言語でデフォルトで使用されている参照セマンティクスが必要な場合class
は、スマートポインターを使用する必要があります。このシナリオでは、複数のクライアントが特定のオブジェクトへの安全なエイリアスを保持する必要があります。ここで、 safeという単語は次の2つの要件をカプセル化します。
- ぶら下がっている参照を避けて、もう存在しないオブジェクトにアクセスしようとしないようにします。
- メモリをリークしないように、それらへのすべての参照よりも長持ちするオブジェクトは避けてください。
これは、スマートポインタが行うことです。参照セマンティクスが必要な場合(および、共有所有権が必要な場合に参照カウントのオーバーヘッドを重要にするようなアルゴリズムではない場合)、スマートポインターを使用する必要があります。
たとえば、同じオブジェクトを複数のコレクションの一部にしたい場合は、参照セマンティクスが必要です。1つのコレクションのオブジェクトを更新するときは、他のすべてのコレクションの同じオブジェクトの表現を一貫して更新する必要があります。この場合、オブジェクトへのスマートポインターをそれらのコレクションに格納します。スマートポインタは、オブジェクトの値ではなく、オブジェクトのIDをカプセル化します。
ただし、エイリアスを作成する必要がない場合は、値のセマンティクスがおそらく信頼できるものです。これは、自動ストレージを使用して(つまり、スタック上で)オブジェクトを宣言するときにC++でデフォルトで取得されるものです。
考慮すべきことの1つは、STLコレクションが値を格納することです。したがって、がある場合は、のvector<T>
コピーがにT
格納されますvector
。参照セマンティクスは必要ないと常に想定していますが、オブジェクトが大きくてコピーに費用がかかる場合、これはとにかくオーバーヘッドになる可能性があります。
このシナリオの可能性を制限するために、C ++ 11には移動操作が付属しており、オブジェクトの古いコピーが不要になったときに、値によってオブジェクトを効率的に転送できます。
ここで、上記の概念を使用して、より直接的に質問に答えようとします。
1)このクラスを値で返すか、スマートポインターで返す必要がありますか?
参照セマンティクスが必要かどうかによって異なります。関数はそのオブジェクトで何をしますか?その関数によって返されるオブジェクトは、多くのクライアントによって共有されることになっていますか?もしそうなら、スマートポインタによって。そうでない場合、効率的な移動操作を定義することは可能ですか(これはほとんどの場合に当てはまります)?もしそうなら、値で。そうでない場合は、スマートポインタによって。
2)クラス内で、ベクターとオブジェクトは通常のメンバーである必要がありますか、それともスマートポインターとして再度格納される必要がありますか?
ベクトルは通常、概念的にオブジェクトの一部であることが意図されているため、通常のメンバーである可能性が高く、そのため、ベクトルの有効期間は、それらを埋め込むオブジェクトの有効期間にバインドされます。このようなシナリオで参照セマンティクスが必要になることはめったにありませんが、必要な場合は、スマートポインターを使用してください。
3)ベクターに、オブジェクトを直接保存する必要がありますか、それともオブジェクトへのスマートポインターを再度保存する必要がありますか?
ポイント1)と同じ答え:それらのオブジェクトを共有する必要がありますか?それらのオブジェクトのエイリアスを保存することになっていますか?それらのオブジェクトへの変更を、それらのオブジェクトを参照するコードのさまざまな部分に表示しますか?その場合は、共有ポインタを使用します。そうでない場合、それらのオブジェクトを効率的にコピーおよび/または移動することは可能ですか?もしそうなら(ほとんどの場合)、値を保存します。そうでない場合は、スマートポインタを保存します。
4)結果クラスで定義されたゲッターは何を返す必要がありますか(つまり、値、参照、またはスマートポインター)?
ポイント2)と同じ答え:返されたオブジェクトをどのように処理するかによって異なります。コードの多くの部分でオブジェクトを共有しますか?その場合は、スマートポインタを返します。それらが1つの部分のみによって独占的に所有される場合は、それらのオブジェクトの移動/コピーが高額であるか、まったく許可されていない場合を除いて、値で返します(ほとんどありません)。その場合は、スマートポインタを返します。
補足として、C++のスマートポインターはJava/ C#参照よりも少し注意が必要です。まず、共有所有権(shared_ptr
)または一意の所有権( )のどちらが必要かによって、スマートポインターには2つの主要な種類がunique_ptr
あります。次に、の循環参照を回避する必要がありshared_ptr
ます。これにより、実行中のコードで到達できなくなった場合でも、オブジェクトのアイランドが作成され、相互に存続します。これが、弱ポインター(weak_ptr
)が存在する理由です。
これらの概念は、当然、オブジェクトの存続期間の管理、または(より一般的には)使用済みリソースの管理に対する責任の概念につながります。たとえば、RAIIイディオム(リソース取得は初期化)、および一般的な例外処理(例外セーフコードの記述がこれらの手法が存在する主な理由の1つです)について読みたいと思うかもしれません。