map::insert不会覆盖已存在key,返回pair.second为false且不修改原值;operator[]则默认构造并允许覆盖,但可能引发不必要的开销。

map::insert 不会覆盖已存在 key
当你用 insert 插入一个已存在的 key,它直接返回 pair,其中 bool 为 false,且不修改原值。这是安全插入的典型场景,比如“只在 key 不存在时才设默认值”。
常见错误是误以为 insert 会更新值,结果逻辑出 bug —— 它真的一点都不动旧值。
-
map.insert({k, v}):若k已存在,v被丢弃,无副作用 -
map.insert(make_pair(k, v))同理,但注意make_pair可能引发额外拷贝(C++17 后通常被优化) - 想“有则更新、无则插入”,得自己判断返回值:
if (!map.insert({k, v}).second) map[k] = v;
operator[] 会默认构造并允许覆盖
map[k] 的行为分两步:如果 k 不存在,先用 value 类型默认构造一个元素(如 int 得 0,string 得空串),再返回其引用;如果存在,就直接返回已有值的引用。所以它天然支持赋值覆盖。
但这个“默认构造”可能代价不小 —— 比如 value 是重型对象(含资源分配),你只是想查一下是否存在,却触发了构造+析构。
立即学习“C++免费学习笔记(深入)”;
-
map[k] = v;总是成功写入,不管k原来有没有 -
map[k]单独使用(不赋值)也会插入默认值,这是很多人踩坑的地方 - 对 const map 或只读场景,
operator[]不可用(它非 const)
性能差异主要来自构造和查找次数
两者底层都调用红黑树查找,时间复杂度同为 O(log n),但实际开销不同:
-
insert:一次查找 + 条件性构造(仅插入新 key 时) -
operator[]:一次查找 + 必然构造(即使 key 存在,也要先默认构造再赋值,或直接覆盖) - 对于 trivial 类型(
int、double),差别几乎不可测;但对于自定义类,operator[]多一次默认构造+可能一次赋值,insert更轻量 - 若你确定 key 一定不存在,
insert还可配合hint(如map.insert(map.end(), {k, v}))实现均摊 O(1) 插入
什么时候该选哪个?
没银弹,看语义优先:
- 要“插入新项,拒绝覆盖” → 用
insert,检查返回值的second - 要“确保 key 存在,值为某值” → 用
operator[],简洁直观 - 要避免默认构造开销(比如 value 是
std::vector或含 mutex 的类)→ 绝对避开operator[],改用insert或try_emplace(C++17) - 高频插入且 key 有序插入(如从小到大)→
insert带hint显著提升性能
真正容易被忽略的是:哪怕你只写了一次 map[k],只要 key 不存在,就已悄悄执行了默认构造 —— 这个隐式行为在调试时很难被意识到。








