我了解unordered_
stl容器会保留许多存储桶,这些存储桶的数量取决于容器中元素的数量。插入时,如果超出某个限制,则容器将重新哈希以使用更多的存储桶,因此每个存储桶的填充较少,并且搜索速度更快。这样会使迭代器无效。
这意味着我不应该将迭代器保留在unordered
容器中。除了我可以的以外,如果我在重新哈希后更新它们。但是我找不到一种可靠的方法来检查insert
(无论是emplace
还是其他原因)引起的重新哈希。
我应该监视bucket_count()
吗?
cppreference说Rehashing occurs only if the new number of elements is greater than max_load_factor()*bucket_count()
。是保证的吗?执行以下操作是否可靠?
bool will_rehash = (max_load_factor()*bucket_count()) > size()+1;
答案 0 :(得分:2)
我不认为一旦散列图增长,就进行重新散列(因为实际上是使用散列函数的过程):
这意味着,可以监视存储桶计数以推断是否应该使迭代器无效(前提是无效发生在重新存储桶时)
#include <iostream>
#include <string>
#include <unordered_map>
using namespace std;
typedef unordered_map<string, string> str_map;
struct my_hash {
void reset(void) { calls_ = 0; }
size_t calls(void) { return calls_; }
size_t operator()(const string& key) const {
++my_hash::calls_;
return hash_fn_(key);
}
private:
str_map native_hash_fn_;
str_map::hasher hash_fn_{native_hash_fn_.hash_function()};
static size_t calls_;
};
size_t my_hash::calls_ = 0;
int main ()
{
typedef unordered_map<string, string, my_hash> myMapType;
myMapType mymap(1, my_hash());
myMapType::hasher hash = mymap.hash_function();
cout << "mymap has " << mymap.bucket_count() << " buckets" << endl;
mymap["abc1"] = "blah"; // add 3 values
mymap["abc2"] = "blah"; // just to see the hash calls tracking
mymap["abc3"] = "blah"; // is working
cout << "hash calls: " << hash.calls() << endl;
hash.reset();
for(size_t i=0; i < 10; ++i) {
mymap[to_string(i)] = "blah";
cout << "buckets: " << mymap.bucket_count() << endl;
cout << "hash calls: " << hash.calls() << endl;
hash.reset();
}
cout << "mymap has " << mymap.bucket_count() << " buckets" << endl;
}
输出:
mymap has 2 buckets
hash calls: 3
buckets: 5
hash calls: 1
buckets: 11
hash calls: 1
buckets: 11
hash calls: 1
buckets: 11
hash calls: 1
buckets: 11
hash calls: 1
buckets: 11
hash calls: 1
buckets: 11
hash calls: 1
buckets: 23
hash calls: 1
buckets: 23
hash calls: 1
buckets: 23
hash calls: 1
mymap has 23 buckets
免责声明:但是,我坚信在更改容器大小之后,引用迭代器不是一个好的编程习惯。即使它可能不会导致某些致命的/未定义的行为,也可能(很可能会)对编程逻辑造成一些副作用。如果使用哈希映射,请考虑使用begin()
迭代器的情况:经过几次插入/插入后,它不再是真正的begin
。即使未进行重新存储,也可能会在其前面安装一些新条目(这可能会影响编程逻辑)。