在使用 C++ 的 std::map
时,配合 erase()
和迭代器的使用是一个经典面试点,也是实际开发中经常出错的地方。本文将深入讲解 erase()
的行为、end()
的本质以及迭代器失效规则,帮助你写出更健壮的代码。
1. erase(it)
的行为
当你使用 erase(it)
删除一个迭代器指向的元素时:
it = myMap.erase(it);
这行代码的效果是:
删除当前迭代器
it
指向的元素;返回一个指向 下一个元素 的迭代器。
如果 it
是最后一个元素呢?
erase(it)
会返回map.end()
,表示迭代器已到达末尾。
std::map<int, std::string> m = {{1, "a"}, {2, "b"}};
auto it = std::prev(m.end()); // 指向 key=2
it = m.erase(it); // 删除 key=2
// 现在 it == m.end()
2. map.end()
是什么?
map.end()
是一个迭代器,表示 容器末尾之后的位置。你不能对其进行解引用(
*it
)或递增(++it
)。它常用于循环终止条件:
for (auto it = m.begin(); it != m.end(); ++it) {// 处理元素
}
3. 面试常问陷阱:删除时如何避免跳过元素?
很多人在遍历过程中删除元素时容易出错。例如:
❌ 错误写法:
for (auto it = m.begin(); it != m.end(); ++it) {if (shouldDelete(it->first)) {m.erase(it); // 危险:it 失效后 ++it 会崩溃}
}
✅ 正确写法:使用 erase()
的返回值
for (auto it = m.begin(); it != m.end(); ) {if (shouldDelete(it->first)) {it = m.erase(it); // 删除并跳到下一个} else {++it;}
}
4. erase 不会导致全部迭代器失效
删除某个元素只会让 指向被删元素的迭代器失效。
其他迭代器仍然有效。
这意味着你可以安全地遍历和删除,只要你不在删除后继续使用原来的迭代器。
5. 总结
情况 | 说明 |
---|---|
it = map.erase(it) | 删除并前进到下一个 |
删除末尾元素 | erase() 返回 end() |
end() 的意义 | 一个不指向任何元素的“哨兵” |
迭代器失效规则 | 只有被删元素的迭代器失效 |