「C++ コンテナーの選択」と呼ばれるよく知られたイメージ (チート シート) があります。用途に合わせて最適な容器を選ぶ流れ図です。
すでに C++11 バージョンがあるかどうか知っている人はいますか?
これは前のものです:
私が知っていることではありませんが、テキストで実行できると思います。list
また、は一般的にそれほど優れたコンテナではなく、 もそうではないため、チャートはわずかにずれていforward_list
ます。どちらのリストも、ニッチなアプリケーション向けの非常に特殊なコンテナです。
このようなチャートを作成するには、次の 2 つの簡単なガイドラインが必要です。
パフォーマンスについて心配することは、通常、最初は役に立ちません。ビッグオーの考慮事項は、数千(またはそれ以上)のアイテムを処理し始めたときにのみ有効になります。
コンテナーには、次の 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
; aforward_list
は、メモリ フットプリントが少ない場合にのみ役立ちます。質問 3:動的サイズ?
{ ... }
、(構文を使用して) 完全な初期化リストを提供できる場合は、 array
. これは、従来の C 配列を置き換えますが、便利な機能を備えています。質問 4:ダブルエンド?
deque
、それ以外の場合は を使用しvector
ます。デフォルトでは、連想コンテナが必要でない限り、選択はvector
. それはSutter と Stroustrup の推薦でもあることがわかりました。
私はマシューの答えが好きですが、フローチャートを次のように言い換えます。
デフォルトでは、もののコンテナーが必要な場合は、を使用しますstd::vector
。したがって、他のすべてのコンテナは、 に代わる機能を提供することによってのみ正当化されstd::vector
ます。
std::vector
アイテムをシャッフルできる必要があるため、そのコンテンツは移動構築可能である必要があります。これはコンテンツに負担をかけるほどの負担ではありません (デフォルトのコンストラクターは必須ではないことに注意してください。などのおかげですemplace
)。ただし、他のコンテナーのほとんどは、特定のコンストラクターを必要としません (これも のおかげですemplace
)。したがって、移動コンストラクターを絶対に実装できないオブジェクトがある場合は、別のものを選択する必要があります。
Astd::deque
は、 の多くのプロパティを持つ一般的な置換std::vector
ですが、両端キューの両端にしか挿入できません。真ん中のインサートは移動が必要です。Astd::list
は、その内容に要件を課しません。
std::vector<bool>
ではありません。まあ、それは標準です。ただし、通常は許可されている操作が禁止されvector
ているため、通常の意味ではありません。std::vector
そして、それは間違いなく含まれていませんbool
s。
vector
したがって、のコンテナーから実際の動作が必要な場合、bool
から取得することはできませんstd::vector<bool>
。そのため、 で期日を迎える必要がありますstd::deque<bool>
。
コンテナ内の要素を検索する必要があり、検索タグを単なるインデックスにできない場合は、 and を優先して放棄する必要がある場合がありstd::vector
ます。キーワード " may " に注意してください。sortedが合理的な代替手段になる場合があります。または、ソート済みを実装するBoost.Container の.set
map
std::vector
flat_set/map
std::vector
現在、これらには 4 つのバリエーションがあり、それぞれに独自のニーズがあります。
map
検索タグが探しているアイテムと同じでない場合は、a を使用します。それ以外の場合は、を使用しset
ます。unordered
がある場合に使用します。O(1)
O(logn)
multi
複数のアイテムに同じ検索タグが必要な場合に使用します。特定の比較操作に基づいてアイテムのコンテナーを常に並べ替える必要がある場合は、set
. または、multi_set
複数のアイテムに同じ値が必要な場合。
または、 sorted を使用できますが、ソートstd::vector
したままにしておく必要があります。
イテレータと参照がいつ無効化されるかが問題になることがあります。他のさまざまな場所にあるアイテムへのイテレータ/ポインタがあるようなアイテムのリストが必要な場合、std::vector
無効化へのアプローチは適切ではない可能性があります。現在のサイズと容量によっては、挿入操作を行うと無効になる場合があります。
std::list
確実な保証を提供します。イテレータとそれに関連付けられた参照/ポインタは、アイテム自体がコンテナから削除されたときにのみ無効になります。std::forward_list
メモリが深刻な懸念事項である場合はそこにあります。
保証が強すぎる場合std::deque
は、弱いが有用な保証を提供します。無効化は途中で挿入すると発生しますが、先頭または末尾で挿入すると、コンテナー内のアイテムへのポインター/参照ではなく、 iteratorの無効化のみが発生します。
std::vector
最後に安価な挿入を提供するだけです(それでも、容量を吹き飛ばすと高価になります).
std::list
パフォーマンスの点では高価ですが (新しく挿入されたアイテムごとにメモリ割り当てが必要です)、一貫性があります。また、事実上パフォーマンス コストなしでアイテムをシャッフルしたり、パフォーマンスを低下させずに同じタイプの他のstd::list
コンテナーとアイテムを交換したりするための不可欠な機能も提供します。物事をたくさんシャッフルする必要がある場合は、 を使用してstd::list
ください。
std::deque
頭と尾で一定時間の挿入/削除を提供しますが、途中での挿入はかなり高価になる可能性があります. したがって、前面だけでなく背面にも物を追加/削除する必要がある場合は、必要なstd::deque
ものかもしれません.
移動セマンティクスのおかげで、std::vector
挿入のパフォーマンスは以前ほど悪くない可能性があることに注意してください。一部の実装では、ムーブ セマンティック ベースのアイテム コピー (いわゆる「スワップティミゼーション」) の形式が実装されていましたが、現在ではムーブは言語の一部であるため、標準で義務付けられています。
std::array
可能な限り少ない動的割り当てが必要な場合は、適切なコンテナーです。これは C 配列の単なるラッパーです。これは、そのサイズがコンパイル時にわかっている必要があることを意味します。それを受け入れることができる場合は、を使用してstd::array
ください。
そうは言っても、 size を使用std::vector
してreserve
ing することは、bounded に対しても同様に機能しますstd::vector
。このように、実際のサイズは変動する可能性があり、メモリ割り当ては 1 つしか取得できません (容量を使い果たした場合を除きます)。
上記のフローチャートの C++11 バージョンを次に示します。[元々は、元の作者であるMikael Perssonに帰属せずに投稿された]