8

たとえば、主にJavaとC#で使用した4冊の本のギャングで説明されているように、通常の(機能的な)設計パターンについてはかなりの経験があると思います。これらの「管理された」言語では、これはあなたがあなたの仕事を成し遂げるために知る必要があるほとんどすべてです。

ただし、C ++の世界では、開発者はすべてのオブジェクトの割り当て、受け渡し、および削除の方法も制御できます。私は原則を理解していますが(他のテキストの中でもStroutrupを読んでいます)、特定のシナリオに最適なメカニズムを決定するにはまだ多くの労力が必要です。これは、メモリ関連のデザインパターンのポートフォリオが役立つ場合です。

たとえば、昨日Results、いくつかのオブジェクトのコンテナであるクラスと、さらに別のタイプのオブジェクトのコレクション(この場合はstd :: vector)を作成する必要がありました。したがって、私が実際に答えることができなかったいくつかの設計上の質問があります。

  1. このクラスを値で返すか、スマートポインターで返す必要がありますか?
  2. クラス内では、ベクターとオブジェクトは通常のメンバーである必要がありますか、それともスマートポインターとして再度格納する必要がありますか?
  3. ベクターでは、オブジェクトを直接保存する必要がありますか、それともオブジェクトへのスマートポインターを再度保存する必要がありますか?
  4. Resultsクラスで定義されたゲッターは何を返す必要がありますか(つまり、値、参照、またはスマートポインター)?

もちろん、スマートポインターはかっこいいですが、構文が乱雑になり、すべてのオブジェクトにmallocを使用することが最適なアプローチであるかどうかはわかりません。

上記の特定の点についての回答に感謝しますが、メモリ関連のデザインパターンに関するより長くより一般的なテキストについてはさらに感謝します。これにより、月曜日にも発生する問題を解決できます。

4

1 に答える 1

26

すべての質問に対する答えは、最終的には同じになります。参照セマンティクスと値セマンティクスのどちらが必要かによって異なります(いくつかの注意点を考慮に入れる必要があります)。

キーワードで宣言されたUDT(ユーザー定義データ型)のJavaやC#などの言語でデフォルトで使用されている参照セマンティクスが必要な場合classは、スマートポインターを使用する必要があります。このシナリオでは、複数のクライアントが特定のオブジェクトへの安全なエイリアスを保持する必要があります。ここで、 safeという単語は次の2つの要件をカプセル化します。

  1. ぶら下がっている参照を避けて、もう存在しないオブジェクトにアクセスしようとしないようにします。
  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つです)について読みたいと思うかもしれません。

于 2013-01-26T18:03:04.103 に答える