初始化用默认构造函数,插入推荐emplace避免拷贝;find只查不改,operator[]会默认构造value;rehash导致迭代器批量失效;自定义key需提供哈希函数和相等比较。

怎么初始化一个空的 unordered_map 并插入键值对
直接用默认构造函数就行,不用预估大小也能工作,但预估能减少 rehash 次数。插入推荐用 emplace 而不是 insert,避免临时对象拷贝。
-
std::unordered_map<:string int> m;</:string>—— 最简初始化 -
m.emplace("key", 42);—— 推荐,原地构造;m["key"] = 42;也行,但会默认构造 value 再赋值 -
m.insert({"key", 42});—— 语法合法,但会多一次 pair 构造,不如 emplace 高效 - 如果知道大概容量(比如要插 1000 个),初始化后立刻调
m.reserve(1000);,否则可能触发多次扩容和重散列
查找元素时 find 和 operator[] 的区别在哪
operator[] 会自动插入默认构造的 value,find 只查不改——这是最常踩的坑,尤其在只读逻辑里误用 [] 导致 map 被污染。
-
auto it = m.find("missing");—— 返回m.end(),安全,不改变容器 -
int x = m["missing"];—— 如果 key 不存在,会插入{"missing", 0}(int 默认为 0),map 大小+1 - 判断存在性必须用
find != end()或count() > 0;别用m["key"] != 0,value 可能本来就是 0,且已悄悄插入 - 自定义 value 类型(比如
std::vector<int></int>)被[]插入时会调默认构造,开销可能不小
为什么迭代器失效比 map 更频繁
unordered_map 的迭代器只在 rehash 时批量失效,单次 insert/erase 不影响其他迭代器——这点常被误解。真正危险的是:rehash 触发条件不透明,且无法禁用。
- 插入导致 size > bucket_count × max_load_factor 时,自动 rehash;
max_load_factor()默认是 1.0,可调低来换稳定性 -
erase(it)后,it立即失效,但其他迭代器仍有效;而erase(key)不影响任何现存迭代器 - 遍历时删除要用
it = m.erase(it)形式,不能写m.erase(it++);——erase返回下一个有效迭代器 - 如果需要稳定迭代器(比如多线程读+偶尔写),要么加锁,要么考虑用
robin_hood::unordered_map这类无动态 rehash 的替代品
自定义类型作 key 时必须提供什么
两个东西:哈希函数(std::hash<t></t> 特化)和相等比较(operator== 或自定义谓词)。缺一不可,否则编译失败或行为未定义。
立即学习“C++免费学习笔记(深入)”;
- 结构体做 key 示例:
struct Point { int x, y; };必须同时提供:bool operator==(const Point& a, const Point& b) { return a.x == b.x && a.y == b.y; }和特化std::hash<point></point> - 哈希函数别直接返回
x + y,容易碰撞;推荐std::hash<int>{}(x) ^ (std::hash<int>{}(y) 或用 <code>std::hash<:size_t></:size_t>组合 - 如果 key 类型已有
==但没哈希,可以传第三个模板参数:std::unordered_map<mykey val myhash></mykey>,不必强求特化全局std::hash - 注意:浮点数作 key 极其危险,
NaN == NaN是 false,哈希值也不可靠,尽量转成整数或字符串再存











