在使用 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() 的意義 | 一個不指向任何元素的“哨兵” |
迭代器失效規則 | 只有被刪元素的迭代器失效 |