本文主要是介绍在遍历中使用 iterator/reverse_iterator 进行 Erase 的用法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
本文转载自 罗朝晖的博客 http://blog.csdn.net/kesalin/article/details/24265303
众所周知,在使用迭代器遍历 STL 容器时,需要特别留意是否在循环中修改了迭代器而导致迭代器失效的情形。下面我来总结一下在对各种容器进行正向和反向遍历过程中删除元素时,正确更新迭代器的用法。本文源码:https://code.csdn.net/snippets/173595
首先,要明白使用正向迭代器(iterator)进行反向遍历是错误的用法,要不干嘛要有反向迭代器呢(reverse_iterator)。其次,根据容器的特性,遍历删除操作的用法可以分为两组,第一组是 list 和 vector,第二组是 map 和 set。
接下来,看看具体怎么个用法。
第一种情形:正向遍历删除元素
对 list 和 vector 来说,它们的 erase 函数会返回下一个迭代器,因此在遍历时,只需要 it = c.erase(it); 即可。
对 map 和 set 来说,它们的 erase 函数返回的 void,而在进行 erase 之后,当前迭代器会失效,无法再用于获取下一个迭代器。因此需要 erase 之前就获取指向下一个元素的迭代器。如:
- tmpIt = it;
- ++it;
- c.erase(tmpIt);
- c.erase(it++);
list 正向遍历删除元素示例(vector 用法相同):
- list<int>::iterator it;
- for (it = l.begin(); it != l.end();)
- {
- if (0 == (*it) % 2) {
- it = l.erase(it);
- }
- else {
- ++it;
- }
- }
map 正向遍历删除元素示例(set 用法相同):
- map<int, int>::iterator mit;
- for (mit = m.begin(); mit != m.end();)
- {
- if (0 == mit->first % 2) {
- m.erase(mit++);
- }
- else {
- ++mit;
- }
- }
第二种情形,反向遍历删除元素
关于正向/反向迭代器的关系,请参考《Effective STL》,在这里我只说明一点,两者相差一个元素,从一个反向迭代器获得对应的正向迭代器需要使用 base() 方法。如下图所示:ri 是指向元素3的反向迭代器,而 i 是 ri.base() 所得到的正想迭代器。
由于所有的 erase 函数都只接受正向迭代器 iterator,所以在进行反向遍历删除元素时,首先需要将 reverse_iterator 转换为 iterator,然后再考虑更新迭代器的问题。
先来分析如何将 reverse_iterator 转换为 iterator。如上图所示,我们想要删除元素3,而 ri.base() 所得到的正向迭代器 i 指向的其实 4 了,因而为了正确地删除元素 3,需要将ri往前(反向的)挪一个位置。也就是说,这一步的删除用法应为:
- c.erase((++rit).base());
或:(想想为什么?,但这个用法不具备可移植性,因为有些 STL 实现不允许修改函数返回的指针)
- c.erase(--(rit.base();
对 list/vector 来说,由于的 erase 能够返回一个有效的正向迭代器,因而只需要将返回的正向迭代器转换为反向迭代器即可。
对 map/set 来说,因为在进行删除操作 l.erase((++rit).base()) 时,迭代器已经更新过了,真是一举两得啊。从这里也可以看出,使用这种先递增后 base() 的转换删除法,代码更清晰。
至此,理论分析完毕,下面我们来看具体的实例。
list 反向遍历删除元素示例(vector 用法相同):
- // erase with reverse_iterator
- list<int>::reverse_iterator rit;
- for (rit = l.rbegin(); rit != l.rend();)
- {
- if (0 == (*rit) % 2) {
- rit = list<int>::reverse_iterator(l.erase((++rit).base()));
- }
- else {
- ++rit;
- }
- }
map 反向遍历删除元素示例(set 用法相同):
- // erase with reverse_iterator
- map<int, int>::reverse_iterator rit;
- for (rit = m.rbegin(); rit != m.rend();)
- {
- if (0 == rit->first % 2) {
- m.erase((++rit).base());
- }
- else {
- ++rit;
- }
- }
OK,删除用法相信大家都明白了,但是,但是,引起迭代器失效的操作还有插入操作呀,相信聪明的你一定能够举一反三正确更新迭代器~~
这篇关于在遍历中使用 iterator/reverse_iterator 进行 Erase 的用法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!