どのSTLコンテナが私のニーズに最適ですか?基本的に10要素幅のコンテナーがあり、その中で最も古い要素(約100万回)をPush_back
処理しながら、pop_front
新しい要素を継続的に格納しています。
現在、タスクにstd::deque
を使用していますが、自分自身を再割り当てする必要がないため、std::list
の方が効率的かどうか疑問に思っていました(または、std::deque
をstd::vector
と間違えているかもしれません)。または、私のニーズにさらに効率的なコンテナがありますか?
追伸ランダムアクセスは必要ありません
無数の答えがあるので、混乱するかもしれませんが、要約すると:
_std::queue
_ を使用します。この理由は簡単です。FIFO構造です。FIFOが必要な場合は、_std::queue
_を使用します。
それはあなたの意図を他の誰か、そしてあなた自身にさえ明確にします。 _std::list
_ または _std::deque
_ はありません。リストはどこでも挿入および削除できますが、これはFIFO構造体が想定していることではありません。また、deque
は両端で追加および削除できます。 FIFO構造体はできません。
これが、queue
を使用する必要がある理由です。
さて、パフォーマンスについて尋ねました。まず、次の重要な経験則を常に覚えておいてください:最初に良いコード、最後にパフォーマンス
その理由は簡単です。清潔さとエレガンスがほとんど常に最後に終わる前にパフォーマンスを追求する人々。彼らのコードはドロドロになります。なぜなら、彼らはそれから何も得られないために良いことをすべて放棄したからです。
最初に適切で読みやすいコードを記述することにより、パフォーマンスの問題のほとんどが解決します。そして、後でパフォーマンスが不足していることに気付いた場合、プロファイラをニースのきれいなコードに追加して、問題の場所を見つけるのは簡単です。
つまり、_std::queue
_は単なるアダプターです。安全なインターフェースを提供しますが、内部で別のコンテナーを使用します。この基礎となるコンテナを選択できます。これにより、かなりの柔軟性が得られます。
それで、どの基礎となるコンテナを使用すべきですか? _std::list
_と_std::deque
_の両方が必要な関数(Push_back()
、pop_front()
、およびfront()
)を提供することを知っています。決めます?
まず、メモリの割り当て(および割り当て解除)は、OSにアクセスして何かを実行することを要求するため、一般に簡単なことではありません。 list
は、何かが追加されるたびにメモリを割り当て、それがなくなるとメモリの割り当てを解除する必要があります。
一方、deque
はチャンクで割り当てます。 list
よりも少ない頻度で割り当てます。リストと考えてください。ただし、各メモリチャンクは複数のノードを保持できます。 (もちろん、私はあなたに 実際にそれがどのように機能するかを学ぶ を提案するでしょう。
したがって、それだけではdeque
のパフォーマンスが向上するはずです。これは、メモリを頻繁に処理しないためです。一定のサイズのデータを処理しているという事実と混合すると、データを最初に通過した後に割り当てる必要はないでしょうが、リストは常に割り当てと割り当て解除を行います。
2番目に理解することは、 キャッシュパフォーマンス です。 RAMに行くのは遅いので、CPUが本当に必要なときは、メモリのチャンクをキャッシュに戻すことでこの時間を最大限に活用できます。deque
はメモリチャンクに割り当てます。このコンテナ内の要素にアクセスすると、CPUがコンテナの残りの部分を戻すことになる可能性があります。これで、deque
への以降のアクセスは高速になります。キャッシュ内。
これは、データが一度に1つずつ割り当てられるリストとは異なります。これは、データがメモリ内のあらゆる場所に分散し、キャッシュのパフォーマンスが低下する可能性があることを意味します。
したがって、それを考慮すると、deque
がより適切な選択であるはずです。これが、queue
を使用する場合のデフォルトのコンテナである理由です。確かに、これはまだ(非常に)経験に基づいた推測にすぎません。特定のテストでdeque
を使用し、他のテストでlist
を使用してこのコードをプロファイルする必要があります。
ただし、コードをクリーンなインターフェイスで動作させ、パフォーマンスを心配することを忘れないでください。
Johnは、list
またはdeque
をラップするとパフォーマンスが低下するという懸念を提起します。繰り返しますが、彼も私も自分でプロファイルせずに確実に言うことはできませんが、コンパイラはqueue
が行う呼び出しをインライン化する可能性があります。つまり、queue.Push()
と言うと、実際にはqueue.container.Push_back()
とだけ言って、関数呼び出しを完全にスキップします。
繰り返しになりますが、これは経験に基づいた推測に過ぎませんが、queue
を使用しても、基礎となるコンテナrawを使用する場合と比較してパフォーマンスは低下しません。前に言ったように、queue
を使用します。これは、クリーンで使いやすく、安全であり、実際に問題のプロファイルとテストになる場合があるためです。
チェックアウト std::queue
。基礎となるコンテナタイプをラップし、デフォルトのコンテナはstd::deque
。
パフォーマンスが本当に重要な場合は、 ブースト循環バッファーライブラリ を確認してください。
私は絶えず
Push_back
新しい要素pop_front
最も古い要素を使用します(約100万回)。
コンピューティングでは、100万人は実際にはそれほど多くありません。他の人が示唆しているように、std::queue
最初の解決策として。あまりにも遅い場合は、プロファイラーを使用してボトルネックを特定し(推測しないでください!)、同じインターフェースを持つ別のコンテナーを使用して再実装します。
何故なの std::queue
?それはすべてPush_back
およびpop_front
。