关于std::list.erase()迭代器行为的困惑:为何未跳过后续元素?
关于std::list erase后迭代器遍历异常的问题
我写了removeOdd函数用来删除std::list<int>里的奇数元素。根据std::list.erase()的文档,它会返回指向被删除元素下一个元素的迭代器,我原本觉得函数会跳过这个后续元素继续遍历,但测试脚本居然通过了?后来给函数加了输出,迭代器出现了好像循环回链表的异常输出,查了文档也搞不懂,求解答。
原removeOdd函数代码:
void removeOdd(list<int>& li) { for(list<int>::iterator it=li.begin(); it!=li.end(); it++) { if((*it)%2) it = li.erase(it); } }
修改后带输出的函数运行输出:
5 2
8
9 6
7 3
4
1 5
2
8
6
3 4
Passed
问题分析与解决
你的代码逻辑核心问题出在it++上。当你调用erase删除元素时,已经把it更新为被删元素的下一个迭代器,但循环末尾的it++会让迭代器再往后走一步,直接跳过了一个元素。测试脚本通过只是刚好测试用例没覆盖到漏删场景,但加输出后暴露了迭代器的异常——本质是迭代器越界导致的未定义行为,看起来就像循环回链表了。
正确的写法要区分两种情况:删除元素时不执行自增,仅在不删除时让迭代器前进。这里提供两种写法:
写法一:使用while循环
void removeOdd(list<int>& li) { auto it = li.begin(); while (it != li.end()) { if (*it % 2) { // erase返回下一个元素的迭代器,直接赋值继续遍历 it = li.erase(it); } else { // 不需要删除时,手动让迭代器前进 ++it; } } }
写法二:调整for循环逻辑
void removeOdd(list<int>& li) { // 把it++从循环头移到内部控制 for (auto it = li.begin(); it != li.end(); ) { if (*it % 2) { it = li.erase(it); } else { ++it; } } }
简单来说:erase返回的迭代器已经帮你定位到下一个要检查的元素,这时候直接用它继续判断就行,不需要额外自增;只有元素不需要删除时,才手动让迭代器前进,这样既不会跳过元素,也不会出现迭代器异常。
内容的提问来源于stack exchange,提问作者Teong Seng Tan
相关产品推荐
相关产品推荐

