特定のSTLコンテナを使用するのはどのシナリオですか?


185

私はC ++に関する本でSTLコンテナー、特にSTLとそのコンテナーに関するセクションを読んでいます。今、私はそれらのそれぞれに固有の特性があることを理解し、それらのすべてを暗記するところです...しかし、まだ理解していないのは、それぞれがどのシナリオで使用されているかです。

説明は何ですか?サンプルコードをお勧めします。


マップ、ベクト、セットなどのことですか?
Thomas Tempelmann、2009年

でも、私は私のquastionの中で使用するのに最適なものであろうものを言うことはできません。この図を見てstackoverflow.com/questions/9329011/...
sergiol

2
@sbi:このタグからC ++ Faqタグを削除し、より新しいC ++ 11に追加します。C++ 11で標準ライブラリコンテナーを効率的に選択するにはどうすればよいですか?
Alok Save

回答:


338

このチートシートは、さまざまなコンテナのかなり良い要約を提供します。

さまざまな使用シナリオで使用するガイドとして、下部のフローチャートを参照してください。

http://linuxsoftware.co.nz/containerchoice.png

作成されたデビッド・ムーアBY-SA 3.0 CCのライセンスを取得


14
このフローチャートはゴールデンです。c#でそのようなものがあったらいいのですが
Bruno

2
更新されたリンク:C ++ Containers Cheat Sheet
Bill Door

3
開始点はvector空ではなく、空でなければなりません。stackoverflow.com/questions/10699265/...
eonil

5
現在、unordered_mapand unordered_set(およびそれらのマルチバリアント)があり、フローチャートには含まれていませんが、順序は気にせず、キーで要素を検索する必要がある場合に適しています。それらの検索は通常、O(log n)ではなくO(1)です。
アイディアカピ2014年

2
@ shuttle87は、そのサイズだけが変わることはありませんが、さらに重要なことに、そのサイズはコンパイル時に決定され、決して変わることはありません。
YoungJohn 2015

188

以下は、私が作成したDavid Mooreのバージョン(上記を参照)に触発されたフローチャートで、新しい標準(C ++ 11)で(ほとんど)最新です。これは私の個人的な見解であり、疑う余地はありませんが、この議論にとって価値があると考えました。

ここに画像の説明を入力してください


4
オリジナルを入手できますか?優れたチャートです。多分ブログやGitHubに固執する?
kevinarpe

1
これは優れたチャートです。誰かが私に「永続的なポジション」の意味を説明できますか?
IDDQD 2016

3
@STALKER永続的な位置とは、コンテナー内の要素へのポインターまたはイテレーターがある場合、そのポインターまたはイテレーターは、コンテナーに何を追加または削除したかに関係なく(同じ要素を指す)有効なままであることを意味します問題の要素ではありません)。
Mikael Persson

1
これは本当に素晴らしいチャートですが、他のものとvector (sorted)は少し矛盾していると思います。これは別のタイプのコンテナではなく、同じですstd::vectorがソートされています。さらに重要なのstd::setは、それがセットを反復する標準の動作である場合に、順序付き反復にforを使用できなかった理由がわかりません。確かに、答えがコンテナの谷の値に秩序立ってアクセスすることについて話している場合は[]、それはsotedでしか行えませんstd::vector。質問「順序が必要とされている」直後しかし、いずれの場合も、決定はなされるべきである
のRA

1
@ user2019840チャートを標準のコンテナーに制限したかったのです。「並べ替えられたベクトル」の代わりに表示されるものは、「flat_set」(Boost.Containerから)、または同等のもの(すべての主要なライブラリまたはコードベースに同等のflat_set、AFAIK)があります。しかし、これらは非標準であり、STLからのかなりの省略です。そして、std :: setまたはstd :: mapを繰り返したくない理由は(少なくとも頻繁ではありません)、そうするのは非常に非効率的です
Mikael Persson 2016年

41

簡単な答え:std::vector特に理由がない限り、すべてに使用します。

「ええ、std::vectorXのためにここではうまくいかない」と思っているケースを見つけたら、Xを基準にしてください。


1
ただし..反復時にアイテムを削除または挿入しないように注意してください...これを避けるためにできるだけconst_iteratorを使用してください..
vrdhn

11
うーん...私は人々がベクトルを使いすぎていると思います。その理由は、「機能しない」ケースは簡単には起こらないためです。そのため、人々は最もよく使用されるコンテナーに固執し、リスト、キューなどを格納するためにそれを誤用します...私の意見では-フローチャートに一致します- 「すべてに合うように見える」を適用するのではなく、使用目的に基づいてコンテナを選択する必要があります。
ブラック

13
@Black Pointは、理論的には遅くなるはずの演算でも、ベクトルは通常より高速です。
Bartek Banachewicz

1
@Vardhan std::remove_ifは、ほとんどの場合、「反復中の削除」アプローチよりも優れています。
fredoverflow

1
いくつかのベンチマークは、この議論の主観性を低下させるのに役立ちます。
Felix D.

11

Scott MeyersによるEffective STLを見てください。STLの使い方を説明するのは得意です。

決定された/未決定の数のオブジェクトを保存し、何も削除しない場合は、ベクターが必要です。これはC配列のデフォルトの置き換えであり、C配列のように機能しますが、オーバーフローしません。そのサイズは、reserve()でも事前に設定できます。

不確定な数のオブジェクトを保存したいが、それらを追加して削除する場合は、おそらくリストが必要です...ベクトルとは異なり、後続の要素を移動せずに要素を削除できるためです。ただし、ベクトルより多くのメモリを必要とし、要素に順次アクセスすることはできません。

一連の要素を取り、それらの要素の一意の値のみを見つけたい場合は、それらをすべてセットに読み込むと、それが実行され、同様に並べ替えられます。

キーと値のペアがたくさんあり、それらをキーでソートしたい場合、マップは役に立ちますが、キーごとに1つの値しか保持できません。キーごとに複数の値が必要な場合は、マップの値としてベクター/リストを使用するか、マルチマップを使用できます。

これはSTLにはありませんが、STLのTR1アップデートに含まれています。キーで検索するキーと値のペアが多数あり、それらの順序を気にしない場合は、ハッシュを使いたい-これはtr1 :: unordered_mapです。私はそれをstdext :: hash_mapと呼ばれるVisual C ++ 7.1で使用しました。マップのO(log n)のルックアップの代わりにO(1)のルックアップがあります。


いくつかの逸話を聞いて、Microsoft hash_mapはあまり良い実装ではないことを示唆しています。私は彼らが上手くやったと思いunordered_mapます。
Mark Ransom

3
リストのうち-「要素に順次アクセスすることはできません。」-私は....あなたが直接要素へのランダムアクセスやインデックスではないことを意味だと思う
トニー・デルロイ

^はい、シーケンシャルアクセスがaの役割とまったく同じlistです。むしろそこに明白なエラー。
underscore_d

7

フローチャートを再設計して、3つのプロパティを追加しました。

  1. STLコンテナーは2つのメインクラスに分かれていると思います。基本的なコンテナとそれらは、基本的なコンテナを利用してポリシーを実装します。
  2. 最初に、フローチャートは、決定プロセスを、私たちが決定する必要のある主要な状況に分割し、次に各ケースについて詳しく説明する必要があります。
  3. 拡張コンテナの中には、内部コンテナとして別の基本コンテナを選択できるものもあります。フローチャートでは、各基本コンテナーを使用できる状況を考慮する必要があります。

フローチャート: ここに画像の説明を入力してください

このリンクで提供される詳細情報。


5

だけ簡単にこれまでに述べた重要な点は、ある(C配列が与えられるように)あなたが連続したメモリが必要な場合は、あなただけ使用することができvectorarrayまたはstring

使用する arrayコンパイル時にサイズがわかっている場合にします。

使用する string汎用コンテナだけでなく、文字タイプだけを操作する必要があり、文字列が必要な場合にます。

vector他のすべてのケースで使用(vectorとにかく、ほとんどの場合、コンテナーのデフォルトの選択です)。

これら3つすべてで、data()メンバー関数を使用して、コンテナーの最初の要素へのポインターを取得できます。


3

それはすべて、何を保存したいか、そして何をコンテナで処理したいかに依存します。以下は、私が最もよく使用する傾向があるコンテナークラスのいくつかの(非常に網羅的ではない)例です。

vector:含まれるオブジェクトごとのメモリオーバーヘッドがほとんどまたはまったくないコンパクトレイアウト。反復するのに効率的です。追加、挿入、および消去は、特に複雑なオブジェクトの場合、コストがかかる可能性があります。含まれているオブジェクトをインデックスで見つけるのは簡単です(例:myVector [10])。Cで配列を使用する場合に使用します。単純なオブジェクト(intなど)が多数ある場合に適しています。reserve()コンテナに多くのオブジェクトを追加する前に使用することを忘れないでください。

list:含まれるオブジェクトごとのメモリオーバーヘッドが小さい。反復するのに効率的です。追加、挿入、および消去は安価です。Cでリンクリストを使用した場所で使用します。

set(およびmultiset):含まれるオブジェクトごとの重要なメモリオーバーヘッド。そのコンテナに特定のオブジェクトが含まれているかどうかをすばやく確認する必要がある場合に使用するか、コンテナを効率的にマージします。

map (そして multimap):含まれるオブジェクトごとの重要なメモリオーバーヘッド。キーと値のペアを保存し、キーで値をすばやく検索する場所を使用します。

zdanによって提案されたチートシートのフローチャートは、より包括的なガイドを提供します。


「含まれるオブジェクトごとの小さなメモリオーバーヘッド」は、リストには当てはまりません。std :: listは二重にリンクされたリストとして実装されているため、保存されたオブジェクトごとに2つのポインタを維持します。
Hanna Khalil

それでも、格納されたオブジェクトごとに2つのポインタを「小さい」と数えます。
2016年

何と比較して?std :: forward_listは、主にオブジェクトごとに格納されるメタデータが少ない(1つのポインターのみ)ことが推奨されているコンテナーです。std :: vectorはオブジェクトごとに0のメタデータを保持します。したがって、2つのポインタは他のコンテナと比較して交渉できません
Hanna Khalil

それはすべて、オブジェクトのサイズに依存します。ベクターには「含まれるオブジェクトごとのメモリオーバーヘッドがほとんどないかまったくないコンパクトレイアウト」があることをすでに述べました。それでも、リストにはセットやマップに比べてメモリオーバーヘッドが小さく、ベクトルよりもメモリオーバーヘッドがわずかに大きいと言えます。TBHを作成しようとしているポイントが本当にわかりません!
2016年

すべてのモードベースのコンテナーは、動的割り当てのためにかなりのオーバーヘッドを持つ傾向があり、無料で提供されることはめったにありません。もちろん、カスタムアロケータを使用している場合を除きます。
MikeMB 2017

2

私が学んだ1つの教訓は、次のとおりです。コンテナタイプをある晴れた日に変更すると大きな驚きが生じる可能性があるため、クラスでラップしてみてください。

class CollectionOfFoo {
    Collection<Foo*> foos;
    .. delegate methods specifically 
}

事前にそれほどコストがかからず、誰かがこの構造体に対して操作xを行うたびに中断したい場合のデバッグ時間を節約できます。

ジョブに最適なデータ構造を選択することになる:

各データ構造はいくつかの操作を提供しますが、これは時間の複雑さを変化させる可能性があります。

O(1)、O(lg N)、O(N)など

基本的に、どの操作が最も多く行われるかを推測し、その操作がO(1)であるデータ構造を使用する必要があります。

シンプルですよね(-:


5
これがイテレータを使用する理由ではありませんか?
Platinum Azure

@PlatinumAzureイテレータであってもメンバーtypedefである必要があります。コンテナタイプを変更する場合は、すべてのイテレータ定義も変更する必要があります...これはc ++ 1xでも修正されました!
vrdhn 2012年

4
好奇心旺盛な方のために、これはC ++ 11での修正です auto myIterator = whateverCollection.begin(); // <-- immune to changes of container type
ブラック

1
思いtypedef Collection<Foo*> CollectionOfFoo;は十分では?
Craig McQueen

5
後で気が変わって単に別のコンテナに委任できるとは考えにくいです。コンテナに依存しないコードの幻想に注意してください
fredoverflow


1

私はこの質問の重複としてマークされている別の質問でこれに答えました。しかし、標準のコンテナを選択する決定については、いくつかの優れた記事を参照するのが良いと思います。

@David Thornleyが答えたように、std :: vectorは、他に特別な必要がない場合の方法です。これは、C ++の作成者であるBjarne Stroustrupによる2014年のブログでのアドバイスです。

こちらが記事のリンクです https://isocpp.org/blog/2014/06/stroustrup-lists

それから引用して

そして、はい、私の推奨は、デフォルトでstd :: vectorを使用することです。

コメントの中で、ユーザー@NathanOliverは、より具体的な測定値を持つ別の優れたブログも提供しています。https://baptiste-wicht.com/posts/2012/12/cpp-benchmark-vector-list-deque.html

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.