【C++】STL容器的迭代器erase方法(转载)
https://zhuanlan.zhihu.com/p/322402705
总结
1、关联容器和序列容器都可以用erase的返回值得到下一个有效迭代器。
2、关联容器还可以直接自增得到下一个有效迭代器。
3、不连续容器list和反向迭代器见下文。
前言
C++有几个坑,其中之一就是迭代器失效问题。虽然在新的c++版本里便利一个标准库容器时可以使用 for (auto e : con) ...;
的语法糖。 但是,偶尔在功能需要你进行索引运算,或者在遍历容器的过程中改变容器时,往往就开始抓瞎了。 这里我的本意就是把这些个容器难用的范例给罗列出来,以飨读者。
轻轻松松的关联容器-erase
对于关联型容器set
,multiset
,map
,multimap
等的索引都是由红黑树实现,那么插入、删除节点时不会影响到其他节点。 需要注意,在实现了erase
方法之后切忌还去使用迭代器,正常递增进入下一轮循环体即可。
auto iter = cont.begin(); while (iter != cont.end();) { //(*iter)->doSomething(); if (shouldDelete(*iter)) { cont.erase(iter++); } else { ++iter; } } // erase方法会返回下一个有效的迭代器 auto iter = cont.begin(); while (iter != cont.end();) { //(*iter)->doSomething(); if (shouldDelete(*iter)) { iter = cont.erase(iter); // 使用iter去承接下一个有效的迭代器 } else { ++iter; } }
战战兢兢的序列型容器-erase
在以vector
, deque
等序列型容器为代表的erase
方法里,则没有上文这么轻松,它们删除当前 迭代器的时候顺便影响了其序列索引后边的所有迭代器,它们删除一个元素之后会导致后面所有的元素前移。 因此只有一种写法
// erase方法会返回下一个有效的迭代器 auto iter = cont.begin(); while (iter != cont.end();) { //(*iter)->doSomething(); if (shouldDelete(*iter)) { iter = cont.erase(iter); // 使用iter去承接下一个有效的迭代器 } else { ++iter; } }
谈到了元素删除,就不得不说到remove
这个方法,vector
容器跟其他的容器不太一样。 remove
方法只是将待删除的元素移动到尾部,并没有真正删除,所以此时要想真正删除则需要搭配erase
方法来真正地删除。
vec.erase(remove(vec.begin(), vec.end(), x), vec.end());
明明白白的不连续容器-erase
对于同样不连续内存容器list
来说,因为其erase
方法的灵活性,使用法则跟关联型容器一致。
但是对于另一个容器forward_list
来说,它根本没有erase
方法,那该怎么办呢? 对于单向列表,为了节省内存和高性能,极简的结构下也带来了使用的问题。 所以在遍历删除的时候需要新增一个辅助迭代器。
auto prev = flst.before_begin(); auto curr = flst.begin(); while (curr != flst.end()) { if (shouldDelete(*curr)) curr = flst.erase_after(prev); else { prev = curr; ++curr; } }
奇奇怪怪的反向迭代器-erase
当你了解到诸多迭代器删除的办法时,心里呼了一口气,这么危险的接口是谁放出来的? 没准想,当你遇到反向遍历+删除时,又是一个坑。 坑就在于erase
的入参只接受正向迭代器。 下面给出反向迭代器的转换示例
auto iter = myList.rbegin(); while (iter != myList.rend();) { if (shouldDelete(*iter)) { iter = decltype(iter)(myList.erase(std::next(iter).base())); } else { ++iter; } } // 节省一点键盘的写法 auto iter = myList.rbegin(); while (iter != myList.rend();) { if (shouldDelete(*iter)) { iter = decltype(iter)(myList.erase(--(iter.base()))); } else { ++iter; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)