私はEffective STLでそれに気づいた
vectorは、デフォルトで使用されるべきシーケンスのタイプです。
どういう意味ですか?効率を無視してもvector
は何でもできるようです。
vector
が実行可能なオプションではないがlist
を使用しなければならないというシナリオを誰かに教えてもらえますか
vector:
list:
一般に、使用しているシーケンシャルコンテナの種類が気にならない場合はvectorを使用しますが、コンテナ内の最後以外の場所で多数の挿入または削除を行っている場合は、必要になります。リストを使用する。ランダムアクセスが必要な場合は、リストではなくベクトルが必要になります。それ以外に、あなたのアプリケーションに基づいてどちらかが必要になることは当然ありますが、一般的に、それらは良いガイドラインです。
要素を頻繁に挿入する必要がない場合は、ベクトルの方が効率的です。リストよりもはるかに優れたCPUキャッシュローカリティを持っています。つまり、ある要素にアクセスすると、veryとなり、次の要素がキャッシュに存在し、低速のRAMを読み取らなくても検索できるようになります。
ここでのほとんどの回答は、1つの重要な詳細を見逃しています。
あなたは何をコンテナに入れたいですか?
それがint
sのコレクションである場合、std::list
は再割り当てが可能であるかどうかに関わらず、すべてのシナリオで失われます。先頭から削除するだけなどです。 list<int>
がvector<int>
を上回る例を用意するのは非常に難しいでしょう。それでも、deque<int>
はリストの使用を正当化するのではなく、より良いか近いかもしれません。
しかし、巨大で醜いデータの塊を扱うのであれば(そしてそれらのうちのいくつかは)、挿入時に過剰割り当てをしたくない場合、再割り当てによるコピーは厄介なことになるでしょう。 list<UglyBlob>
よりvector<UglyBlob>
。
それでも、あなたがvector<UglyBlob*>
あるいはvector<shared_ptr<UglyBlob> >
にさえ切り替えるならば、再び - リストは遅れます。
そのため、アクセスパターン、ターゲット要素数などは依然として比較に影響しますが、私の考えでは - 要素のサイズ - コピーのコストなど.
Std :: listの特別な機能の1つは、スプライシング(リストの一部または全体を別のリストにリンクまたは移動すること)です。
または、あなたのコンテンツがコピーするのに非常に高価であるならば。そのような場合、例えば、リストを使ってコレクションをソートする方が安価な場合があります。
コレクションが小さい(そして内容がコピーするのに特に高価ではない)場合でも、どこかに挿入して消去したとしても、ベクトルはまだリストを上回る可能性があります。リストは各ノードを個別に割り当てるので、いくつかの単純なオブジェクトを移動するよりもはるかにコストがかかる可能性があります。
それほど難しいルールはないと思います。それはあなたがコンテナに対して何をしたいのか、そしてコンテナがどのくらいの大きさになるのか、そして含まれている型にもよります。ベクトルは、内容を単一の連続ブロックとして割り当てるため、一般的にリストを切り捨てます(基本的に動的に割り当てられる配列です。ほとんどの場合、配列は最も効率的な方法です)。
私のクラスの生徒たちは、ベクトルを使うほうが効果的であることを説明できないようですが、リストを使うように忠告しているときは、とても幸せそうです。
これが私の理解の仕方です
Lists:各項目には次または前の要素へのアドレスが含まれているため、この機能を使用すると、項目が並べ替えられていなくても順序を変えることができません。あなたの記憶は断片化しています。しかし、それには他にも非常に大きな利点があります。項目を簡単に挿入/削除できるのは、ポインターを変更することだけが必要だからです。欠点:ランダムな単一のアイテムを読むには、正しいアドレスが見つかるまであるアイテムから別のアイテムにジャンプする必要があります。
Vectors:ベクトルを使うとき、メモリは通常の配列のようにもっと組織化されています:各n番目の項目は(n-1)番目の項目の直後と(n + 1)番目の項目の直前に格納されます。なぜリストよりいいの?高速ランダムアクセスが可能だからです。ベクトル内のアイテムのサイズがわかっていて、それらがメモリ内で連続している場合は、n番目のアイテムがどこにあるかを簡単に予測できます。あなたが欲しいものを読むためにリストのすべての項目を閲覧する必要はありません、ベクトルで、あなたはあなたができないリストで、あなたは直接それを読みます。一方、ベクトル配列を変更したり、値を変更したりするのははるかに遅くなります。
リストは、メモリ内で追加/削除できるオブジェクトを追跡するのにより適しています。ベクトルは、大量の単一アイテムから要素にアクセスする場合に適しています。
リストの最適化方法はわかりませんが、高速読み取りアクセスが必要な場合はベクトルを使用する必要があることを知っておく必要があります。STLがリストを高速化するのは、ベクトルより読み取りアクセスが速いからではありません。
基本的にベクトルは自動メモリ管理を備えた配列です。データはメモリ内で連続しています。途中でデータを挿入しようとすると、コストがかかります。
リストでは、データは関連性のないメモリ位置に保存されます。真ん中に挿入することは、新しいもののために場所を空けるためにデータの一部をコピーすることを含みません。
より具体的にあなたの質問に答えるために私は引用します このページ
ベクトルは一般に、要素にアクセスし、シーケンスの最後に要素を追加または削除するのに時間的に最も効率的です。末尾以外の位置で要素を挿入または削除する操作の場合、それらはdequesおよびlistよりもパフォーマンスが悪く、listよりも一貫性のない反復子および参照を持ちます。
イテレータを無効にすることはできません。
あなたがシーケンスの途中で多くの挿入または削除があるとき。例えばメモリマネージャ.
リストを使用する理由の1つは、反復子の有効性を維持することです。もう1つは、アイテムをプッシュするときにベクトルを再割り当てしたくない場合です。これは、reserve()を賢く使用することで管理できますが、場合によっては、単にリストを使用するほうが簡単か、または実行可能な場合があります。
オブジェクトをコンテナ間で移動したい場合は、list::splice
を使用できます。
例えば、グラフ分割アルゴリズムは、増加する数のコンテナ間で再帰的に分割される一定数のオブジェクトを有することができる。オブジェクトは一度初期化する必要があり、常にメモリ内の同じ場所に残ります。再割り当てするよりも再リンクすることでそれらを再配置する方がはるかに速いです。
編集:ライブラリがC++ 0xを実装する準備をしているので、サブシーケンスをリストにつなぎ合わせる一般的なケースは、シーケンスの長さとともに線形の複雑さになりつつあります。これは、splice
(now)がシーケンス内の要素数を数えるためにシーケンスを反復処理する必要があるためです。単純にリストを数えて再リンクするのは、他の方法よりもずっと速く、リスト全体または単一の要素を接合することは、一定の複雑さを伴う特別な場合です。しかし、つなぎ合わせのシーケンスが長い場合は、古くなった、より準拠していない、より優れたコンテナを探してみる必要があるかもしれません。
list
を使用する必要がある唯一の厳格な規則は、ポインタをコンテナの要素に配布する必要がある場合です。
vector
とは異なり、要素のメモリは再割り当てされません。もしそうなら、あなたは未使用のメモリへのポインタを持っているかもしれません。それは、せいぜい大きく、いいえ、そして、悪くてもSEGFAULT
です。
(技術的には*_ptr
のvector
も機能しますが、その場合はlist
をエミュレートしているので、これは単なるセマンティクスです。)
他のソフトルールはコンテナの真ん中に要素を挿入することで起こりうるパフォーマンスの問題と関係があります。そこでlist
が望ましいでしょう。