STL中 如何在遍历中使用 iterator/reverse_iterator 删除元素
来源:互联网 发布:mediawiki 数据库配置 编辑:程序博客网 时间:2024/06/05 04:04
~~~~我的生活,我的点点滴滴!!
参考大神http://www.cnblogs.com/kesalin/p/cpp_stl.html
众所周知,在使用迭代器遍历 STL 容器时,需要特别留意是否在循环中修改了迭代器而导致迭代器失效的情形。
下面我来总结一下在对各种容器进行正向和反向遍历过程中删除元素时,正确更新迭代器的用法。本文完整源码
首先,要明白使用正向迭代器(iterator)进行反向遍历是错误的用法,要不干嘛要有反向迭代器呢(reverse_iterator)。
其次,根据容器的特性,遍历删除操作的用法可以分为两组,第一组是 list 和 vector,第二组是 map 和 set。
接下来,看看具体怎么个用法。
先总结一句话: 对于使用迭代器时,如果用了删除即erase,那他会使迭代器的位置+1 所以这个时候 for循环里面就不能++iter之类的操作了,
故如果遍历删除元素,那就在循环体里面自加或自减,for的第三个参数就不要写了
std::vector<XXX*>::iterator iter;for( iter = XX.begin(); iter != XX.end();) {auto sp = (*iter);if( isOK ) {iter = m_fallObject.erase(iter);}else{++iter;}}for语句里面就不要在写上++iter了
第一种情形:正向遍历删除元素
对 list 和 vector 来说,它们的 erase 函数会返回下一个迭代器,因此在遍历时,只需要 it = c.erase(it); 即可。
对 map 和 set 来说,它们的 erase 函数返回的 void,而在进行 erase 之后,当前迭代器会失效,无法再用于获取下一个迭代器。因此需要 erase 之前就获取指向下一个元素的迭代器。如:
tmpIt = it;
++it;
c.erase(tmpIt);
利用后缀++操作符的特性(先创建副本,然后再递增迭代器,然后返回副本)上面的三行代码可以简化为一行:
c.erase(it++);
下面来看实例:
list 正向遍历删除元素示例(vector 用法相同):
// erase with iterator list<int>::iterator it; for (it = l.begin(); it != l.end();) { if (0 == (*it) % 2) { it = l.erase(it); } else { ++it; } }
map 正向遍历删除元素示例(set 用法相同):
// erase with iterator 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())); //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,删除用法相信大家都明白了,但是,但是,引起迭代器失效的操作还有插入操作呀,相信聪明的你一定能够举一反三正确更新迭代器~~
测试样例代码 点击打开链接
- STL中 如何在遍历中使用 iterator/reverse_iterator 删除元素
- 如何在遍历中使用 iterator/reverse_iterator 删除元素
- 如何在遍历中使用 iterator/reverse_iterator 删除元素
- 在遍历中使用 iterator/reverse_iterator 进行 Erase 的用法
- 在遍历中使用 iterator/reverse_iterator 进行 Erase 的用法
- 在遍历中使用 iterator/reverse_iterator 进行 Erase 的用法
- 在遍历中使用 iterator/reverse_iterator 进行 Erase 的用法
- 在遍历中使用 iterator/reverse_iterator 进行 Erase 的用法
- 在遍历中使用 iterator/reverse_iterator 进行 Erase 的用法
- stl在遍历过程中删除元素
- stl容器在循环遍历中删除元素的方式
- STL容器:在遍历的过程中删除元素
- STL中正确使用ERASE()方法遍历删除元素
- STL中list,遍历删除元素注意事项
- STL迭代器遍历中删除元素问题
- Java集合中删除元素使用Iterator
- 使用iterator删除list,map中元素
- Iterator遍历器删除集合中元素抛异常
- 用gcc编译opencv程序出错
- 【CSE 104 – Assignment 01 – Java单链表建立】
- oracle在windows命令行启动
- 仿QQ5.0缩放式侧滑栏的实现
- lua函数说明
- STL中 如何在遍历中使用 iterator/reverse_iterator 删除元素
- visitedUserIdvisitedUserIdvisitedUserIdvisitedUserIdvisitedUserIdvisitedUserIdvisitedUserIdvisitedUs
- Cocos2d-JS环境配置教程
- 毕达哥斯拉三元组poj1305
- 【冒泡排序、选择排序、插入排序总结】
- SpringMVC与Spring集成
- 内存中的分区以及堆区和栈区的区别
- Failed to fetch URL https://dl-ssl.google.com/android/repository/addons_list-1.xml, reason: Connecti
- 输入3个学员的姓名,动态分配内存保存学员姓名,并在最后输出.