私が見ているように、ポインタとオブジェクトのどちらを使用するかを決定する際には、いくつかの要因が関係しています。
1.ポリモーフィズムが必要ですか、それとも必要ありませんか?
基本クラスオブジェクトのコンテナを維持し、その中にさまざまな派生クラスのオブジェクトを格納する場合は、仮想関数呼び出しが正しく解決されないため、ポインタを使用する必要があります。
2.保存するオブジェクトのサイズとコピー操作への適合性
ポインタがオブジェクトよりも優先される主な理由の1つは、コンテナで実行されるさまざまな操作に、コンテナに格納されているオブジェクトのコピーの作成が含まれることです。これは、多くの格納操作(例std::vector<>::push_back()
、またはstd::map<>::insert()
)、一部の取得操作(例std::vector<>::operator[]
、およびオブジェクトをローカル変数に格納する)、およびコンテナによって「内部的に」実行される操作の一部(たとえば、再割り当て)の場合です。容量を超えて成長したときのベクトル、またはの再ハッシュstd::unordered_map<>
。コンテナの選択方法とその使用方法によっては、コピー操作の重要性が低くなる場合があることに注意してください(たとえばstd::vector<>::reserve()
、十分なスペースの割り当てstd::vector<>::emplace_back()
、ストレージの使用、取得した要素のローカルコピーを作成しない場合は、コピーがないことを意味する場合があります)。これまでに作られた)。
ただし、多数のコピーが作成されることが予想される場合(または、既存のコードをプロファイリングすると多くのコピーが作成されることが判明した場合)、ポインターは小さく、メモリ内で適切に配置されているため、オブジェクトの代わりにポインターを使用すると明らかに役立ちます。繰り返しになりますが、格納するオブジェクトが実際にポインタよりも小さい場合、これはあまり意味がありません。
3.コンテナとその内容に対して実行するその他の操作
扱っているオブジェクトがポインターよりも大きく、大量のコピー操作が予想される場合でも、ポインターの使用は必ずしも好ましいとは限りません。多数の中型オブジェクト(たとえば、それぞれ16バイト)を格納し、コンテナー全体を繰り返し処理して、ある種の統計計算を実行する必要がある状況を考えてみます。これらのオブジェクトをベクトルに直接格納すると、反復中に優れたキャッシュ効率が得られます。1つのオブジェクトを取得すると、キャッシュライン全体がメモリから取得されるため、次のいくつかのオブジェクトの取得がはるかに高速になります。これは通常、ポインタが使用されている場合には当てはまりません。逆に、要素を取得した後は、ポインタを逆参照する必要があり、キャッシュされていない可能性のあるメモリ領域から別の移動操作が発生します。
明らかに、それはすべて、保存するオブジェクトのタイプとサイズ、および実行する操作のタイプと頻度に依存します。扱っているオブジェクトがGUIアプリケーションのさまざまなタイプのウィンドウ、ボタン、およびメニューである場合は、ポインターを使用してポリモーフィズムを利用することをお勧めします。一方、サイズと形状がすべて同じであるコンパクトな要素の巨大な構造を扱っている場合、実行する操作に頻繁な反復または一括コピーが含まれる場合は、オブジェクトを直接保存することをお勧めします。また、両方を試し、メモリと時間のベンチマークの結果に基づいて決定しないと、決定を下すのが難しい場合もあります。
最後に、ポインタを使用することになった場合は、構築しているコンテナが、ヒープに割り当てているオブジェクトの最終的な所有者であるか、一時的なポインタを維持しているだけであるかを検討してください。コンテナがこれらのオブジェクトの所有者である場合は、生のポインタではなく、スマートポインタを使用することをお勧めします。