「C ++コンテナーの選択」と呼ばれるよく知られたイメージ(チートシート)があります。必要な用途に最適なコンテナを選択するためのフローチャートです。
すでにC ++ 11バージョンがあるかどうか誰かが知っていますか?
これは前のものです:
「C ++コンテナーの選択」と呼ばれるよく知られたイメージ(チートシート)があります。必要な用途に最適なコンテナを選択するためのフローチャートです。
すでにC ++ 11バージョンがあるかどうか誰かが知っていますか?
これは前のものです:
回答:
私が知っていることではありませんが、テキストで行うことができると思います。また、list
一般的にはそれほど良いコンテナではなく、どちらもそうではないため、チャートは少しずれていますforward_list
。どちらのリストも、ニッチアプリケーションに特化したコンテナです。
このようなグラフを作成するには、次の2つの簡単なガイドラインが必要です。
通常、最初はパフォーマンスを気にする必要はありません。大きなOの考慮事項は、数千(またはそれ以上)のアイテムの処理を開始したときにのみ実際に始まります。
コンテナには2つの大きなカテゴリがあります。
find
オペレーションがありますその後、あなたがそれらの上にいくつかのアダプタを構築することができます:stack
、queue
、priority_queue
。アダプターはここでは省略します。認識できるように十分に特殊化されています。
質問1:連想?
質問1.1:注文しましたか?
unordered_
コンテナーを使用します。それ以外の場合は、従来の注文済みの対応物を使用します。質問1.2:別のキー?
map
、それ以外の場合はset
質問1.3:重複していますか?
multi
場合は、を使用します。それ以外の場合は使用しないでください。例:
一意のIDが関連付けられた複数の人物がいて、そのIDからできるだけ簡単に人物データを取得したいとします。
が欲しい find
機能を、これ連想コンテナ
1.1。私は秩序をあまり気にすることができなかったので、unordered_
コンテナを
1.2。私のキー(ID)は、関連付けられている値とは異なるため、map
1.3。IDは一意であるため、重複して侵入することはできません。
最終的な答えは次のとおりstd::unordered_map<ID, PersonData>
です。
質問2:メモリは安定していますか?
list
質問2.1:どっち?
list
; a forward_list
は、メモリ使用量が少ない場合にのみ役立ちます。質問3:動的なサイズですか?
{ ... }
構文)、そして使用array
。従来のCアレイを置き換えますが、便利な機能を備えています。質問4:ダブルエンド?
deque
場合は、を使用しvector
ます。それ以外の場合はを使用します。連想コンテナが必要でない限り、デフォルトではが選択されることに注意してくださいvector
。それはまた、SutterとStroustrupの推奨事項でもあります。
array
デフォルトの構成可能なタイプを必要としません。2)multi
sを選択することは、許可された重複についてではなく、それらを保持することが重要であるかどうかについての詳細です(非multi
コンテナに重複を置くことができますが、保持されるのは1つだけです)。
map.find(key)
はより美味しいstd::find(map.begin(), map.end(), [&](decltype(map.front()) p) { return p.first < key; }));
ので、意味的にfind
は、からの関数ではなく、メンバー関数であることが重要<algorithm>
です。O(1)対O(log n)については、セマンティクスには影響しません。例から「効率的に」を削除し、「簡単に」置き換えます。
deque
このプロパティも持っていると思いましたか?
deque
では、どちらかの端でプッシュ/ポップした場合にのみ要素が安定します。途中で挿入/消去を開始すると、作成されたギャップを埋めるために最大N / 2個の要素がシャッフルされます。
私はマシューの答えが好きですが、フローチャートを次のように書き直します。
デフォルトでは、もののコンテナが必要な場合はを使用しますstd::vector
。したがって、他のすべてのコンテナは、いくつかの代替機能を提供することによってのみ正当化されますstd::vector
ます。
std::vector
アイテムをシャッフルできるようにする必要があるため、コンテンツは移動構成可能である必要があります。これは、内容(デフォルトコンストラクタがあることに注意してください上の場所へのひどい負担ではありません必要はありませんおかげで、emplace
など)。ただし、他のほとんどのコンテナは、特定のコンストラクタを必要としません(これものおかげですemplace
)。したがって、移動コンストラクタを絶対に実装できないオブジェクトがある場合は、別のものを選択する必要があります。
A std::deque
は、のプロパティの多くを備えた一般的な置き換えstd::vector
ですが、両端キューの両端にのみ挿入できます。真ん中のインサートは移動が必要です。A std::list
はその内容を要求しません。
std::vector<bool>
ではありません。まあ、それは標準です。しかしvector
、std::vector
通常許可されている操作は禁止されているため、通常の意味ではありません。そしてそれは間違いなくbool
sを含まない。
したがって、sのvector
コンテナから実際の動作が必要な場合bool
、それをから取得することはありませんstd::vector<bool>
。したがって、で期限を設定する必要がありますstd::deque<bool>
。
あなたは、コンテナ内の要素を見つける必要がある、と検索タグだけでインデックスすることができない場合は、放棄する必要があるかもしれないstd::vector
の賛成でset
とmap
。キーワード「かもしれない」に注意してください。ソートstd::vector
は時々合理的な代替手段です。またはflat_set/map
並べ替えを実装するBoost.Containerのstd::vector
。
現在、これらには4つのバリエーションがあり、それぞれ独自のニーズがあります。
map
検索タグが、探しているアイテムと同じでない場合は、aを使用します。それ以外の場合はを使用しset
ます。unordered
ならない場合に使用します。O(1)
O(logn)
。multi
複数のアイテムに同じ検索タグを付ける必要がある場合に使用します。特定の比較演算に基づいて常にアイテムのコンテナーをソートする必要がある場合は、を使用できますset
。またはmulti_set
、同じ値を持つ複数のアイテムが必要な場合。
または、ソートを使用できます std::vector
したままにする必要があります。
イテレータと参照が無効化されると、問題になることがあります。他のさまざまな場所にあるアイテムへのイテレータ/ポインタがあるように、アイテムのリストが必要な場合は、std::vector
、無効化へののアプローチは適切でない場合があります。現在のサイズと容量によっては、挿入操作によって無効化が発生する場合があります。
std::list
確かな保証を提供します。イテレータとそれに関連付けられた参照/ポインタは、アイテム自体がコンテナから削除されたときにのみ無効になります。std::forward_list
記憶が深刻な問題である場合に存在します。
それが強すぎる保証である場合std::deque
、より弱いが有用な保証を提供します。無効化は真ん中の挿入によって発生しますが、先頭または末尾に挿入すると、コンテナー内のアイテムへのポインター/参照ではなく、反復子のみが無効化されます。
std::vector
最後に安価な挿入のみを提供します(それでも、容量をブローすると高価になります)。
std::list
パフォーマンスの点で高価です(新しく挿入された各アイテムにはメモリ割り当てが必要です)が、一貫しています。また、パフォーマンスコストをほとんどかけずにアイテムをシャッフルしたりstd::list
、パフォーマンスを低下させずに同じタイプの他のコンテナーとアイテムを交換したりするために必要な場合もあります。たくさんのことをシャッフルする必要がある場合は、を使用してくださいstd::list
。
std::deque
頭と尾に一定時間の挿入/取り外しを提供しますが、中央への挿入はかなり高価になる可能性があります。したがって、前面だけでなく背面からも物を追加/削除する必要がある場合は、必要な場合がありstd::deque
ます。
移動のセマンティクスのおかげで、std::vector
挿入のパフォーマンスは以前ほど悪くないことに注意してください。一部の実装では、セマンティックベースのアイテムのコピー(いわゆる「スワップティマイゼーション」)の移動の形式を実装していましたが、移動は言語の一部であるため、標準で義務付けられています。
std::array
可能な限り少ない動的割り当てが必要な場合は、良いコンテナです。これはC配列の単なるラッパーです。つまり、そのサイズはコンパイル時にわかっている必要があります。それで生活できるなら、を使ってくださいstd::array
。
そうは言っても、サイズの使用std::vector
とreserve
ingは、制限付きの場合にも同様に機能しますstd::vector
。このように、実際のサイズは変わる可能性があり、1つのメモリ割り当てしか得られません(容量を大きくしない限り)。
std::sort
もstd::inplace_merge
興味深いものです。学ぶためにニースと!std::lower_bound
std::vector::insert
flat_set
flat_map
vector<bool>
ですvector<char>
。
std::allocator<T>
がそのアラインメントをサポートしていない場合(およびそれがサポートされない理由がわからない場合)、独自のカスタムアロケーターをいつでも使用できます。
std::vector::resize
は、値を取らないオーバーロードがあります(新しいサイズを取るだけです。新しい要素はデフォルトでインプレースで構築されます)。また、コンパイラーが値パラメーターを持つように宣言されている場合でも、コンパイラーが値パラメーターを適切に位置合わせできないのはなぜですか?
bitset
事前にサイズがわかっている場合はブール値en.cppreference.com/w/cpp/utility/bitset
上記のフローチャートのC ++ 11バージョンを以下に示します。[もともとは元の作者に帰属せずに投稿、ミカエル・パーション ]
これは簡単なスピンですが、おそらく作業が必要です
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バージョンとは大きく異なることに気づくかもしれません。これは、主にリンクノードが本当に好きではないためです。いくつかのまれな状況を除いて、リンクされたノードコンテナーは通常、リンクされていないコンテナーに比べてパフォーマンスが劣ります。これらの状況がわからない場合、およびブーストへのアクセス権がある場合は、リンクされたノードコンテナーを使用しないでください。(std :: list、std :: slist、std :: map、std :: multimap、std :: set、std :: multiset)。(A)これはコードで扱うものの99.99%であり、(B)多数の要素には異なるコンテナーではなくカスタムアルゴリズムが必要であるため、このリストは主に中小規模のコンテナーに焦点を当てています。