web-dev-qa-db-ja.com

サイズが事前にわかっている場合のstd :: mapの初期化

std::mapを初期化します。今のところ::insertを使用していますが、割り当てたいサイズをすでに知っているので、計算時間を浪費しているように感じます。固定サイズのマップを割り当ててマップを埋める方法はありますか?

30
vanna

いいえ、マップのメンバーは内部的にツリー構造に保存されます。格納するキーと値がわかるまで、ツリーを構築する方法はありません。

40
Bo Persson

簡単な答えは次のとおりです。はい、これは可能ですが、簡単ではありません。マップのカスタムアロケーターを定義する必要があります。基本的な考え方は、カスタムアロケーターがマップ用の単一のメモリブロックを確保することです。マップは新しいノードを必要とするため、アロケータは事前​​に割り当てられたブロック内のアドレスを割り当てます。このようなもの:

std::map<KeyType, ValueType, std::less<KeyType>, MyAllocator> myMap;

myMap.get_allocator().reserve( nodeSize * numberOfNodes );

ただし、対処しなければならない問題がいくつかあります。

まず、各マップノードのサイズや、マップが実行する割り当ての数が実際にはわかりません。これらは内部実装の詳細です。実験して調べることはできますが、結果が異なるコンパイラー(または同じコンパイラーの将来のバージョン)で保持されるとは想定できません。したがって、「固定」サイズマップの割り当てについて心配する必要はありません。むしろ、目標はほんの一握りに必要な割り当ての数を減らすことです。

第二に、削除をサポートしたい場合、この戦略はかなり複雑になります。

第三に、メモリアライメントの問題を忘れないでください。アロケータが返すポインタは、メモリが保存するさまざまなタイプのオブジェクトに適切に整列する必要があります。

言われていることはすべて、これを試す前に、それが必要であることを確認してください。メモリの割り当ては非常に高価になる可能性がありますが、プログラムの問題であると想定すべきではありません。調べるために測定します。より自然に事前割り当てを可能にする代替戦略も検討する必要があります。たとえば、ソートされたリストまたはstd :: unordered_map。

23
Peter Ruderman

あなたはblock allocatorsについて話している。しかし、実装するのは難しいです。そのような難しいことを考える前に測定してください。とにかく Boost にはブロックアロケーターの実装に関する記事があります。または、既に実装されている事前割り当てマップを使用します Stree

2
Denis Ermolin

これがあなたの質問に答えるかどうかはわかりませんが、Boost.Containerには、スペースを予約できるflat_mapがあります。基本的に、これは(キー、値)ペアのソートされたベクトルとして見ることができます。ただし、入力が既に一定である場合は、最初はstd::mapを使用しません。追加のヒント:入力が並べ替えられていることもわかっている場合は、最大限のパフォーマンスを得るためにヒント付きの挿入を使用できます。

1
gast128