以来
- これらは両方とも連続したメモリコンテナです。
- 機能的には、dequeには、ベクトルが持つほとんどすべてのものがありますが、前面に挿入する方が効率的であるため、それ以上のものがあります。
なぜwhould誰もが好むstd::vector
にstd::deque
?
以来
なぜwhould誰もが好むstd::vector
にstd::deque
?
回答:
aの要素は、メモリ内で連続しdeque
ていません。vector
要素はであることが保証されています。したがって、連続した配列を必要とするプレーンCライブラリと対話する必要がある場合、または空間的局所性を(非常に)気にする場合は、をお勧めしますvector
。さらに、いくつかの余分な簿記があるので、他の操作はおそらく(わずかに)同等のvector
操作よりも高価です。一方、の多くの/大きなインスタンスを使用vector
すると、不要なヒープの断片化が発生する可能性があります(への呼び出しが遅くなりますnew
)。
また、StackOverflowの他の場所で指摘されているように、ここにはもっと良い議論があります:http://www.gotw.ca/gotw/054.htm。
違いを知るには、deque
一般的にどのように実装されているかを知る必要があります。メモリは同じサイズのブロックに割り当てられ、それらは(配列または場合によってはベクトルとして)一緒にチェーンされます。
したがって、n番目の要素を見つけるには、適切なブロックを見つけて、その中の要素にアクセスします。これは常に正確に2回のルックアップであるため、一定の時間ですが、それでもベクトルを超えています。
vector
また、C APIであるか、ポインターと長さを取得できるという点でより用途が広いため、連続したバッファーが必要なAPIでもうまく機能します。(したがって、下にベクトルまたは通常の配列を配置し、メモリブロックからAPIを呼び出すことができます)。
deque
その最大の利点はどこにありますか:
これらの2つ目はあまり知られていませんが、コレクションサイズが非常に大きい場合:
過去に大規模なコレクションを扱っていて、隣接モデルからブロックモデルに移行したとき、32ビットシステムでメモリが不足する前に、約5倍の大規模なコレクションを格納できました。これは、再割り当てするときに、要素をコピーする前に、実際には古いブロックと新しいブロックを保存する必要があったためです。
以上のことをすべて言っても、std::deque
「楽観的な」メモリ割り当てを使用するシステムでは問題が発生する可能性があります。の再割り当てのために大きなバッファサイズを要求しようとするvector
と、ある時点でが拒否されるbad_alloc
可能性がありますが、アロケータの楽観的な性質により、aによって要求された小さなバッファの要求が常に許可されるdeque
可能性があります。いくつかのメモリを取得しようとするプロセスを強制終了するオペレーティングシステム。どちらを選んでも、あまり快適ではないかもしれません。
このような場合の回避策は、システムレベルのフラグを設定して楽観的な割り当てを上書きするか(常に実行可能とは限りません)、メモリ使用量などをチェックする独自のアロケータを使用するなど、メモリを手動で管理することです。明らかに理想的ではありません。(ベクトルを好むようにあなたの質問に答えるかもしれません...)
vectorとdequeの両方を複数回実装しました。dequeは、実装の観点からは非常に複雑です。この複雑さは、より多くのコードとより複雑なコードに変換されます。したがって、ベクトルではなく両端キューを選択すると、通常、コードサイズがヒットします。また、コードでベクトルが優れているもの(つまり、push_back)のみを使用している場合は、速度がわずかに低下する可能性があります。
両端キューが必要な場合は、dequeが明らかに勝者です。しかし、ほとんどの挿入と消去を後ろで行っている場合は、ベクトルが明らかに勝者になります。確信が持てない場合は、typedefを使用してコンテナーを宣言し(簡単に切り替えられるようにします)、測定します。
vector
ます。)以下にリンクされている実装を回答に記述しました。これは、同じくらい高速ですvector
が、はるかに広く適用できます(たとえば、高速キューを作成する場合)。
std::deque
継続的なメモリは保証されていません。また、インデックス付きアクセスの場合は多少遅くなることがよくあります。dequeは通常、「ベクトルのリスト」として実装されます。
http://www.cplusplus.com/reference/stl/deque/によると、「ベクトルとは異なり、dequeはすべての要素が連続した格納場所にあるとは限らないため、ポインタ演算による安全なアクセスの可能性が排除されます。」
Dequeは、必ずしも連続したメモリレイアウトを持っているとは限らないため、もう少し複雑です。その機能が必要な場合は、両端キューを使用しないでください。
(以前、私の答えは標準化の欠如をもたらしました(上記と同じソースから、「両端キューは特定のライブラリによって異なる方法で実装される可能性があります」)が、実際にはほぼすべての標準ライブラリデータ型に当てはまります。)
std::deque
と同じくらい標準化されていstd::vector
ます。の複雑さの要件std::deque
は、連続したストレージで満たすことができるとは思いません。
deque
連続ストレージで満たすことができない複雑さの要件はどれですか?
deque
。つまり、両端に挿入しても、既存の要素への参照が無効にならないということです。この要件は、不連続なメモリを意味します。
それぞれのケースの性能テストを行うのは良い考えだと思います。そして、このテストに基づいて決定を下します。
私はほとんどの場合std::deque
よりも好むでしょうstd::vector
。
vector
でした。なぜそうではないのかは当然のことと推測できます。deque
理由は不明ですが、不特定のテストからあなたが好むと言うことは答えではありません。
これらのテスト結果(ソースを使用)によると、両端キューよりもベクトルを好まないでしょう。
もちろん、アプリ/環境でテストする必要がありますが、要約すると次のようになります。
一方では、vectorはdequeよりも単純に高速であることがよくあります。dequeのすべての機能が実際に必要でない場合は、ベクトルを使用してください。
一方、ベクターが提供しない機能が必要な場合もあります。その場合は、両端キューを使用する必要があります。たとえば、dequeを使用せずに、またアルゴリズムを大幅に変更せずに、このコードを書き直そうとする人に挑戦します。
push_back
とpop_back
操作、deque<int>
少なくとも20%の高速化よりも常にあるvector<int>
私のテスト(O3とGCC)インチ 私はのはなぜ推測deque
のようなもののための標準的な選択肢ですstd::stack
...
std::deque
最大ブロックサイズは非常に小さいため(正しく思い出せば最大16バイト、おそらく32バイト)、現実的なアプリケーションではあまりうまく機能しません。A (または16?それは少数だが)と同じ性能特性に関する持つ各要素が動的に割り当てられ、。他の実装では最大ブロックサイズが異なるため、異なるプラットフォームで比較的同じパフォーマンス特性を持つコードを作成することは困難です。deque<T>
sizeof(T) > 8
vector<T*>
deque