unordered_map
コンテナは、map
のようなツリーではなく、バケットを使用して実装されているため、reserve
メソッドがあります。
バケットがある:
要素は、そのキーのハッシュ値に基づいて割り当てられているコンテナの内部ハッシュテーブルのスロット。バケットには0から(bucket_count-1)までの番号が付けられます。 (source)
単一のバケットは、可変数の項目を保持します。この数値はload_factor
に基づいています。 load_factor
が一定のしきい値に達すると、コンテナはバケットの数を増やしてマップを再ハッシュします。
reserve(n)
を呼び出すと、コンテナは少なくともn
のアイテムを保持するのに十分なバケットを作成します。
これは、n
に直接バケット数を設定し、ハッシュテーブル全体の再構築をトリガーするrehash(n)
とは対照的です。
も参照してください:Pre-allocating buckets in a C++ unordered_map
編集コメント
に応じて、私はコメントで提起質問に対する正確な答えを知らない、と私の予備調査として実りを証明していないとして、私は実験的にテストすることにしました。参考のため
、質問がに沸く:
n個の要素のためのバケットを予約すると、n個の要素のためにメモリを割り当てると同じである場合は、説明していただけますか?
this answerによると、正確unordered_map
に割り当てられた領域のサイズを取得することは難しいと信頼できないです。だから私はVisual Studio 2015の診断ツールを利用することに決めました。次のように
まず、私のテストケースは次のとおりです。
#include <unordered_map>
#include <cstdint>
struct Foo
{
Foo() : x(0.0f), y(0.0f), z(0.0f) { }
float x;
float y;
float z;
};
int32_t main(int32_t argc, char** argv)
{
std::unordered_map<uint32_t, Foo> mapNoReserve;
std::unordered_map<uint32_t, Foo> mapReserve;
// --> Snapshot A
mapReserve.reserve(1000);
// --> Snapshot B
for(uint32_t i = 0; i < 1000; ++i)
{
mapNoReserve.insert(std::make_pair(i, Foo()));
mapReserve.insert(std::make_pair(i, Foo()));
}
// -> Snapshot C
return 0;
}
コメントが示す
が、私はメモリのスナップショットを取りました。
結果は以下の通りであった:
スナップショットA:
┌──────────────┬──────────────┬──────────────┐
| Map | Size (Bytes) | Bucket Count |
|--------------|--------------|--------------|
| mapNoReserve | 64 | 8 |
| mapReserve | 64 | 8 |
└──────────────┴──────────────┴──────────────┚
スナップショットB:
┌──────────────┬──────────────┬──────────────┐
| Map | Size (Bytes) | Bucket Count |
|--------------|--------------|--------------|
| mapNoReserve | 64 | 8 |
| mapReserve | 8231 | 1024 |
└──────────────┴──────────────┴──────────────┚
スナップショットC:
┌──────────────┬──────────────┬──────────────┐
| Map | Size (Bytes) | Bucket Count |
|--------------|--------------|--------------|
| mapNoReserve | 24024 | 1024 |
| mapReserve | 24024 | 1024 |
└──────────────┴──────────────┴──────────────┚
解釈:あなたがスナップショットから見ることができるように
、我々が、彼らにreserve
呼ばれていたとしても1に要素を追加し始めると、両方のマップのサイズが大きくなることが表示されます。
reserve
はまだメモリが割り当てられていても利点がありますか? (1)バケットのメモリをあらかじめ割り当てておき、(2)rehash
の必要性を防ぐことができます。これは前述のように完全にマップを再構築します。
演算子[]、insert()またはemplace()が.reserve()以外のメモリを使用する代わりにメモリを割り当てることを決定するために使用した方法を省略できますか? – nos
@nos私はすべての呼び出しでアセンブリを踏んで、最終的に 'operator new()'と 'malloc()'と呼ばれる何らかの 'List_buy()'または 'BuyNode()'呼び出しで終了しました。 – Mikubyte