165

新しいシステムをゼロから設計します。STL を使用して、特定の長寿命オブジェクトのリストとマップを保存します。

質問: オブジェクトが確実にコピー コンストラクターを持ち、オブジェクトのコピーを STL コンテナー内に格納する必要がありますか?それとも、ライフとスコープを自分で管理し、それらのオブジェクトへのポインターを STL コンテナーに格納するだけの方が一般的には良いですか?

これは詳細がやや不足していることを認識していますが、これらのソリューションの両方が可能であることを知っているので、「理論的な」より良い答えが存在する場合はそれを探しています。

ポインタで遊ぶことの 2 つの非常に明白な欠点: 1) STL を超えた範囲で、これらのオブジェクトの割り当て/割り当て解除を自分で管理する必要があります。2) スタック上に一時オブジェクトを作成してコンテナーに追加することができません。

私が見逃しているものは他にありますか?

4

10 に答える 10

68

人々はポインターを使用することの効率性に関心を持っているためです。

std::vector の使用を検討していて、更新が少なく、頻繁にコレクションを反復処理し、オブジェクトの「コピー」を格納する非ポリモーフィック型である場合は、参照の局所性が向上するため、より効率的になります。

おお、更新が一般的な場合、ポインターを保存するとコピー/再配置のコストが節約されます。

于 2008-09-26T19:18:20.930 に答える
47

これは実際の状況によって異なります。

オブジェクトが小さく、オブジェクトのコピーが軽量である場合、データを stl コンテナー内に格納するのは簡単で、ライフタイム管理について心配する必要がないため、管理が簡単だと思います。

オブジェクトが大きく、デフォルトのコンストラクターを持つことが意味をなさない場合、またはオブジェクトのコピーが高価な場合は、おそらくポインターを使用して格納することをお勧めします。

オブジェクトへのポインターを使用する場合は、Boost Pointer Container Libraryを参照してください。このブースト ライブラリは、動的に割り当てられたオブジェクトで使用するために、すべての STL コンテナーをラップします。

各ポインター コンテナー (ptr_vector など) は、オブジェクトがコンテナーに追加されるとそのオブジェクトの所有権を取得し、それらのオブジェクトの有効期間を管理します。また、参照によって ptr_ コンテナ内のすべての要素にアクセスします。これにより、次のようなことができます

class BigExpensive { ... }

// create a pointer vector
ptr_vector<BigExpensive> bigVector;
bigVector.push_back( new BigExpensive( "Lexus", 57700 ) );
bigVector.push_back( new BigExpensive( "House", 15000000 );

// get a reference to the first element
MyClass& expensiveItem = bigList[0];
expensiveItem.sell();

これらのクラスは STL コンテナーをラップし、すべての STL アルゴリズムで動作するため、非常に便利です。

コンテナー内のポインターの所有権を呼び出し元に転送する機能もあります (ほとんどのコンテナーの release 関数を介して)。

于 2008-09-26T19:41:30.203 に答える
39

多形オブジェクトを格納している場合は、常に基底クラス ポインターのコレクションを使用する必要があります。

つまり、コレクションにさまざまな派生型を格納する予定がある場合は、ポインターを格納するか、スライシング デーモンに食べられる必要があります。

于 2008-09-26T19:13:25.340 に答える
22

開催から3年経ってしまい申し訳ありませんが、ここで注意事項を…

私の最後の大きなプロジェクトでは、中心的なデータ構造はかなり単純なオブジェクトのセットでした。プロジェクトを開始して約 1 年が経過し、要件が進化するにつれて、オブジェクトは実際にはポリモーフィックである必要があることに気付きました。データ構造を基本クラス ポインターのセットに修正し、オブジェクト ストレージやキャストなどのすべての巻き添え被害を処理するには、数週間の困難で厄介な脳手術が必要でした。新しいコードが機能していることを確信するのに 2 か月かかりました。ところで、C++ のオブジェクト モデルの設計がいかに優れているかを考えさせられました。

私の現在の大きなプロジェクトでは、中心的なデータ構造はかなり単純なオブジェクトのセットです。プロジェクトに着手してから約 1 年 (たまたま今日)、オブジェクトは実際にはポリモーフィックである必要があることに気付きました。ネットに戻ると、このスレッドが見つかり、Boost ポインター コンテナー ライブラリへの Nick のリンクが見つかりました。これはまさに前回すべてを修正するために書かなければならなかったことなので、今回は試してみます。

とにかく、私にとっての教訓:あなたの仕様が100%石で鋳造されていない場合は、ポインタを探してください。そうすれば、後で多くの作業を節約できる可能性があります.

于 2012-01-26T11:01:39.193 に答える
19

両方の世界を最大限に活用してみませんか。スマート ポインター (boost::shared_ptrまたは などstd::shared_ptr) のコンテナーを作成します。メモリを管理する必要はなく、大規模なコピー操作に対処する必要もありません。

于 2008-09-26T19:15:17.583 に答える
11

一般に、オブジェクトを STL コンテナーに直接格納するのが最も簡単で効率的であり、オブジェクトを使用するのに最も簡単です。

オブジェクト自体がコピー不可能な構文を持っているか、抽象基本型である場合は、ポインターを格納する必要があります (最も簡単なのは shared_ptr を使用することです)。

于 2008-09-26T19:16:22.853 に答える
3

違いがよくわかるようです。オブジェクトが小さくてコピーしやすい場合は、必ずそれらを保存してください。

そうでない場合は、ヒープに割り当てたものにスマート ポインター (参照カウント スマート ポインターである auto_ptr ではない) を格納することを検討します。明らかに、スマート ポインターを選択した場合、一時スタックに割り当てられたオブジェクトを格納することはできません (前述のとおり)。

@ Torbjörnはスライスについて良い点を述べています。

于 2008-09-26T19:14:10.220 に答える
3

コンテナは完全なオブジェクトではなくポインタをコピーするだけなので、ポインタを使用するとより効率的になります。

ここには、STL コンテナーとスマート ポインターに関する有用な情報がいくつかあります。

標準コンテナで std::auto_ptr<> を使用するのが間違っているのはなぜですか?

于 2008-09-26T19:14:44.620 に答える
2

オブジェクトがコード内の別の場所で参照される場合は、boost::shared_ptr のベクトルに格納します。これにより、ベクトルのサイズを変更しても、オブジェクトへのポインターが有効なままになります。

すなわち:

std::vector<boost::shared_ptr<protocol> > protocols;
...
connection c(protocols[0].get()); // pointer to protocol stays valid even if resized

他の誰もオブジェクトへのポインターを保存しない場合、またはリストが拡大縮小しない場合は、単純なオブジェクトとして保存してください。

std::vector<protocol> protocols;
connection c(protocols[0]); // value-semantics, takes a copy of the protocol
于 2008-09-27T05:54:38.090 に答える
1

この質問はしばらくの間私を悩ませてきました。

私はポインタを保存することに傾倒していますが、あなたには当てはまらないかもしれないいくつかの追加要件 (SWIG lua ラッパー) があります。

この投稿で最も重要な点は、オブジェクトを使用して自分でテストすることです

今日、これを行って、1000 万個のオブジェクトのコレクションでメンバー関数を 500 回呼び出す速度をテストしました。

この関数は、xdir と ydir (すべて float メンバー変数) に基づいて x と y を更新します。

std::list を使用して両方のタイプのオブジェクトを保持しましたが、オブジェクトをリストに格納する方がポインターを使用するよりもわずかに高速であることがわかりました。一方、パフォーマンスは非常に近いものだったので、アプリケーションでどのように使用されるかにかかっています.

参考までに、私のハードウェアで -O3 を使用すると、ポインターが完了するまでに 41 秒かかり、生のオブジェクトが完了するまでに 30 秒かかりました。

于 2013-07-19T01:33:36.953 に答える