最推荐用 for (auto& p : my_map) 遍历 map,避免值拷贝和类型错误;修改 value 用 auto& p,只读用 const auto& p;遍历 const map 必须用 cbegin()/cend();边遍历边删除应使用 erase(it++)。

用 for (auto& p : my_map) 最安全
直接基于范围的 for 循环是当前 C++11 及以上最推荐的方式,既简洁又不易出错。它自动推导键值对类型,避免手动写 std::pair 或搞混 first/second。
常见错误是写成 for (auto p : my_map)(值拷贝),尤其当 value 是大对象时性能明显下降;或者误用 auto& key : my_map 导致编译失败——map 的每个元素是 std::pair<const key t></const>,不是单独的 key。
- 要修改 value:用
auto& p,然后改p.second - 只读遍历:用
const auto& p更明确,也允许绑定到临时对象 - 想单独取 key 或 value?直接
p.first/p.second,别试图解构(C++17 之前不支持结构化绑定在 range-for 中自动展开)
begin() / end() 迭代器遍历要注意 const 正确性
手写迭代器循环仍常见于需要中途 erase() 或做条件跳过时。但容易忽略 const 容器和非常量迭代器之间的冲突。
典型报错:error: no viable conversion from 'std::map<int std::string>::const_iterator' to 'std::map<int std::string>::iterator'</int></int>,往往是因为对 const map 调用了非 const begin()。
立即学习“C++免费学习笔记(深入)”;
- 遍历 const map:必须用
cbegin()/cend(),或显式声明const_iterator - 需要边遍历边删除?用
erase(it++)形式,不能写erase(it); ++it;——erase()返回下一个有效迭代器,后者会导致迭代器失效后二次递增 - 别用
!=比较 map 迭代器和end()的结果来判断结束——虽然通常可行,但标准只要求 map 迭代器支持==和!=,不保证有效
按 key 排序是 map 的默认行为,别误以为要额外 sort
std::map 底层是红黑树,插入即排序。遍历时天然按键升序,不需要、也不能调用 std::sort 或自定义比较器重排。
有人试图传入 std::greater 创建降序 map,却在遍历时发现顺序“不对”——其实是忘了遍历本身仍是按容器内部顺序走,而这个顺序就是构造时指定的比较规则决定的。
- 要降序遍历?建 map 时用
std::map<key val std::greater>> my_map;</key> - 已有升序 map,临时想降序访问?只能用反向迭代器:
rbegin()/rend(),注意类型是reverse_iterator,解引用后仍是pair - 别在循环里反复调用
my_map.find(key)来“找顺序”,那是 O(log n) × n,纯属浪费
遍历中修改 key 会破坏 map 结构
map 的 key 是 const 的,任何试图通过迭代器修改 p.first 的操作都会编译失败。强行绕过(比如用 const_cast)会导致未定义行为——红黑树节点位置不再匹配 key 值,后续查找、插入、遍历全不可信。
真实需求往往是“更新某条记录的 key”,这本质是删除旧 key + 插入新 key。直接改不行,得拆成两步。
- 安全做法:先
auto val = std::move(p.second),再my_map.erase(p.first),最后my_map.emplace(new_key, std::move(val)) - 如果只是想根据 value 更新逻辑,完全不需要碰 key,
p.second是可写的(除非 map 本身是 const) - 用
std::unordered_map?它不保序,但 key 同样不可原地修改;且哈希表中改 key 后不 rehash,等于直接破坏桶结构











