「C++ Container choice」と呼ばれるよく知られた画像(チートシート)があります。これは、使用目的に最適なコンテナを選択するためのフローチャートです。
すでにC++ 11バージョンが存在するかどうかを知っていますか?
これは前のものです:
私が知っているわけではありませんが、テキストで行うことができます。また、list
は一般的にそれほど良いコンテナではなく、forward_list
。両方のリストは、ニッチアプリケーション用の非常に特殊なコンテナです。
このようなチャートを作成するには、2つの簡単なガイドラインが必要です。
通常、パフォーマンスについて心配することは最初は役に立ちません。 Oの大きな考慮事項は、数千(またはそれ以上)のアイテムの処理を開始したときにのみ有効です。
コンテナには2つの大きなカテゴリがあります。
find
操作がありますそして、それらの上にいくつかのアダプターを構築できます:stack
、queue
、priority_queue
。アダプターはここでは省略しますが、認識できるほど十分に特殊化されています。
質問1:連想的?
質問1.1:Ordered?
unordered_
コンテナ、それ以外の場合は従来の順序付けられた対応物を使用します。質問1.2:Separate Key?
map
を使用し、そうでない場合はset
を使用します質問1.3:Duplicates?
multi
を使用します。それ以外の場合は使用しません。例:
一意のIDが関連付けられた複数の人物がいて、できるだけ簡単にそのIDから人物データを取得したいとします。
find
関数、つまり連想コンテナが必要です
1.1。私は順序についてあまり気にすることができなかったので、unordered_
コンテナ
1.2。私のキー(ID)は、関連付けられている値とは別であるため、map
1.3。 IDは一意であるため、重複することはありません。
最後の答えは:std::unordered_map<ID, PersonData>
。
質問2:安定したメモリ?
list
を使用します質問2.1:Which?
list
;で解決します。 forward_list
は、メモリフットプリントが少ない場合にのみ役立ちます。質問3:動的サイズ?
{ ... }
構文)、array
を使用します。従来のC配列を置き換えますが、便利な機能を備えています。質問4:Double-ended?
deque
を使用します。それ以外の場合は、vector
を使用します。デフォルトでは、連想コンテナが必要でない限り、vector
が選択されることに注意してください。 Sutter and Stroustrupの推奨 であることが判明しました。
Matthieuの答えは気に入っていますが、フローチャートを次のように言い換えます。
デフォルトでは、もののコンテナが必要な場合は、_std::vector
_を使用します。したがって、他のすべてのコンテナーは、_std::vector
_の代替機能を提供することによってのみ正当化されます。
_std::vector
_では、アイテムをシャッフルできる必要があるため、そのコンテンツは移動構築可能である必要があります。これは、コンテンツに与えるひどい負担ではありません(デフォルトのコンストラクターは不要です、emplace
などのおかげです) 。ただし、他のコンテナーのほとんどは特定のコンストラクターを必要としません(これもemplace
のおかげです)。したがって、移動コンストラクタを絶対にcannot実装するオブジェクトがある場合は、別のものを選択する必要があります。
_std::deque
_は一般的な置換で、_std::vector
_の多くのプロパティを持ちますが、両端キューの両端にしか挿入できません。中央のインサートは移動が必要です。 _std::list
_は、その内容に要件を設けません。
_std::vector<bool>
_は...ではありません。まあ、それは標準です。しかし、通常の意味ではvector
ではありません。_std::vector
_が通常許可する操作は禁止されているためです。そして、最も確かににはbool
sが含まれていません。
したがって、vector
sのコンテナーから実際のbool
動作が必要な場合は、_std::vector<bool>
_から取得することはできません。したがって、_std::deque<bool>
_を支払う必要があります。
コンテナ内の要素を見つける必要があり、検索タグを単なるインデックスにできない場合は、set
およびmap
を優先して_std::vector
_を放棄する必要がある場合があります。キーワード「may」に注意してください。ソートされた_std::vector
_は、合理的な代替手段である場合があります。または、Boost.Containerの _flat_set/map
_ は、ソートされた_std::vector
_を実装します。
現在、これらには4つのバリエーションがあり、それぞれにニーズがあります。
map
を使用します。それ以外の場合は、set
を使用します。O(1)
である必要がある場合は、unordered
を使用します。 O(logn)
ではなく。multi
を使用します。特定の比較操作に基づいて常にアイテムのコンテナをソートする必要がある場合は、set
を使用できます。または、同じ値を持つために複数のアイテムが必要な場合は_multi_set
_。
または、並べ替えられた_std::vector
_を使用できますが、並べ替えておく必要があります。
イテレータと参照が無効化されることが懸念される場合があります。アイテムのリストが必要な場合(他のさまざまな場所にあるアイテムへのイテレーター/ポインターがある場合)、無効化に対する_std::vector
_のアプローチは適切ではない可能性があります。現在のサイズと容量によっては、挿入操作によって無効化が発生する場合があります。
_std::list
_は確固たる保証を提供します。イテレータとそれに関連する参照/ポインタは、アイテム自体がコンテナから削除されたときにのみ無効になります。 _std::forward_list
_は、メモリが深刻な問題である場合に存在します。
それがあまりにも強力な保証である場合、_std::deque
_はより弱いが有用な保証を提供します。無効化は中央への挿入から生じますが、先頭または末尾への挿入は、コンテナ内のアイテムへのポインタ/参照ではなく、反復子の無効化のみを引き起こします。
_std::vector
_は、最後に安価な挿入のみを提供します(そして、それでも、容量を爆破すると高価になります)。
_std::list
_はパフォーマンスの点で高価です(新しく挿入された各アイテムにはメモリ割り当てがかかります)が、consistentですまた、実質的にパフォーマンスコストをかけずにアイテムをシャッフルしたり、パフォーマンスを損なうことなく同じタイプの他の_std::list
_コンテナとアイテムを交換したりする場合に不可欠な機能も提供します。シャッフルa lotする必要がある場合は、_std::list
_を使用します。
_std::deque
_は、先頭と末尾での一定時間の挿入/削除を提供しますが、中央への挿入はかなり高価になる可能性があります。したがって、前面だけでなく背面からものを追加/削除する必要がある場合は、_std::deque
_が必要な場合があります。
移動セマンティクスのおかげで、_std::vector
_挿入のパフォーマンスは以前ほど悪くないことに注意してください。一部の実装では、ムーブセマンティックベースのアイテムコピー(いわゆる「スワップ化」)の形式を実装しましたが、現在、ムービングは言語の一部であり、標準で義務付けられています。
_std::array
_は、できるだけ少ない動的割り当てが必要な場合に適したコンテナです。これは、C配列の単なるラッパーです。つまり、サイズはcompile-timeで認識されている必要があります。それと一緒に暮らすことができる場合は、_std::array
_を使用します。
つまり、サイズに_std::vector
_とreserve
ingを使用すると、境界のある_std::vector
_に対しても同様に機能します。このように、実際のサイズは変化する可能性があり、1つのメモリ割り当てしか取得できません(容量を使い果たしていない限り)。
上記のフローチャートのC++ 11バージョンを以下に示します。 [元の著者に帰属することなく元々投稿された Mikael Persson ]
簡単な手順を示しますが、おそらく作業が必要です
Should the container let you manage the order of the elements?
Yes:
Will the container contain always exactly the same number of elements?
Yes:
Does the container need a fast move operator?
Yes: std::vector
No: std::array
No:
Do you absolutely need stable iterators? (be certain!)
Yes: boost::stable_vector (as a last case fallback, std::list)
No:
Do inserts happen only at the ends?
Yes: std::deque
No: std::vector
No:
Are keys associated with Values?
Yes:
Do the keys need to be sorted?
Yes:
Are there more than one value per key?
Yes: boost::flat_map (as a last case fallback, std::map)
No: boost::flat_multimap (as a last case fallback, std::map)
No:
Are there more than one value per key?
Yes: std::unordered_multimap
No: std::unordered_map
No:
Are elements read then removed in a certain order?
Yes:
Order is:
Ordered by element: std::priority_queue
First in First out: std::queue
First in Last out: std::stack
Other: Custom based on std::vector?????
No:
Should the elements be sorted by value?
Yes: boost::flat_set
No: std::vector
主にリンクされたノードが好きではないという事実により、これがC++ 03バージョンとwildlyで異なることに気付くかもしれません。いくつかのまれな状況を除き、リンクされたノードコンテナは、通常、リンクされていないコンテナによってパフォーマンスが低下する可能性があります。これらの状況がわからない場合、およびブーストへのアクセス権がある場合は、リンクノードコンテナーを使用しないでください。 (std :: list、std :: slist、std :: map、std :: multimap、std :: set、std :: multiset)。このリストは主に中小規模のコンテナに焦点を当てています。なぜなら、(A)これはコードで扱うものの99.99%であり、(B)多数の要素には異なるコンテナではなくカスタムアルゴリズムが必要だからです。