c++ 迭代器失效学习 effective-STL 9条
https://www.cnblogs.com/newbeeyu/p/6883122.html
结合 effective STL 条款9
https://www.cnblogs.com/fnlingnzb-learner/p/9300073.html
C++迭代器失效的几种情况总结
一、序列式容器(数组式容器)
对于序列式容器(如vector,deque),序列式容器就是数组式容器,删除当前的iterator会使后面所有元素的iterator都失效。
这是因为vetor,deque使用了连续分配的内存,删除一个元素导致后面所有的元素会向前移动一个位置。 所以不能使用erase(iter++)的方式,还好erase方法可以返回下一个有效的iterator。
for (iter = cont.begin(); iter != cont.end();)
{
(*it)->doSomething();
if (shouldDelete(*iter))
iter = cont.erase(iter); //erase删除元素,返回下一个迭代器 这个是 序列容器
else
++iter;
}
上面是对序列容器删除的正确做法
二、关联式容器
对于关联容器(如map, set,multimap,multiset),删除当前的iterator,仅仅会使当前的iterator失效,只要在erase时,递增当前iterator即可。
这是因为map之类的容器,使用了红黑树来实现,插入、删除一个结点不会对其他结点造成影响。erase迭代器只是被删元素的迭代器失效,但是返回值为void,所以要采用erase(iter++)的方式删除迭代器。
伪代码!!!!!
for (iter = cont.begin(); it != cont.end();)
{
(*iter)->doSomething();
if (shouldDelete(*iter))
cont.erase(iter++);
else
++iter;
}
上面这个是对的 ok //删除操作引发迭代器失效
for (iter = dataMap.begin(); iter != dataMap.end();iter++)
{
int nKey = iter->first;
string strValue = iter->second;
if (nKey % 2 == 0)
{
dataMap.erase(iter); //错误
}
}
解析:dataMap.erase(iter++);这句话分三步走,先把iter传值到erase里面,然后iter自增,然后执行erase,所以iter在失效前已经自增了。
错误的一行 那是因为 关联容器 删除当前迭代器后 当前迭代器那就是无效的了 然后再次 ++ 肯定不行啊 只能向上面的那样才是正确的 骚操作 dataMap.erase(iter++) 这样才是正确的
三、链表式容器
对于链表式容器(如list),删除当前的iterator,仅仅会使当前的iterator失效,这是因为list之类的容器,使用了链表来实现,插入、删除一个结点不会对其他结点造成影响。
只要在erase时,递增当前iterator即可,并且erase方法可以返回下一个有效的iterator。
for (iter = cont.begin(); it != cont.end();)
{
(*iter)->doSomething();
if (shouldDelete(*iter))
cont.erase(iter++);
else
++iter;
}
effective stl 条款9里面的总结
要删除容器中特定值的所有对象:
如果容器是vector,string,或者deque ,则使用erase-remove习惯的用法;
如果容器是list,则使用list::remove.
如果容器是标准的关联容器,则使用它的erase 成员函数
要删除容器中满足特定判别式的所有对象:
如果容器是vector,string,deque,则使用erase_remove_if的习惯用法
如果容器是list,则使用list::remove_if
如果容器是一个标准关联容器,则使用remove_copy_if和swap,或者写一个循环来遍历容器中的所有元素,记住当把迭代器传给erase时,要对它进行后缀递增
要在循环内部做某些操作:
如果容器是标准序列容器 vector deque,则写一个循环来遍历容器中的元素,记住每次调用erase时,要用他的返回值更新迭代器。!!!!!!!
如果容器是标准关联容器,则写一个循环来遍历容器中的元素,记住当把迭代器传给erase时,要对迭代器做后续递增。(链表类容器也是这么干 因为他们两个的结构类是一个是 树一个链表)!!
---------------------
四、总结
迭代器失效分三种情况考虑,也是分三种数据结构考虑,分别为数组型,链表型,树型数据结构。
数组型数据结构:该数据结构的元素是分配在连续的内存中,insert和erase操作,都会使得删除点和插入点之后的元素挪位置,所以,插入点和删除掉之后的迭代器全部失效,也就是说insert(*iter)(或erase(*iter)),然后在iter++,是没有意义的。解决方法:erase(*iter)的返回值是下一个有效迭代器的值。 iter =cont.erase(iter);
链表型数据结构:对于list型的数据结构,使用了不连续分配的内存,删除运算使指向删除位置的迭代器失效,但是不会失效其他迭代器.解决办法两种,erase(*iter)会返回下一个有效迭代器的值,或者erase(iter++).
树形数据结构: 使用红黑树来存储数据,插入不会使得任何迭代器失效;删除运算使指向删除位置的迭代器失效,但是不会失效其他迭代器.erase迭代器只是被删元素的迭代器失效,但是返回值为void,所以要采用erase(iter++)的方式删除迭代器。
注意:经过erase(iter)之后的迭代器完全失效,该迭代器iter不能参与任何运算,包括iter++,*ite
c++ 迭代器失效学习 effective-STL 9条的更多相关文章
- 容器使用的12条军规——《Effective+STL中文版》试读
容器使用的12条军规——<Effective+STL中文版>试读 还 记的自己早年在学校学习c++的时候,老师根本就没有讲STL,导致了自己后来跟人说 起会C++的时候总是被鄙视, ...
- C++ STL中迭代器失效的问题
my_container.erase(iter); 其中my_container是STL的某种容器,iter是指向这个容器中某个元素的迭代器.如果不是在for,while循环中,这种方式删除元素没有问 ...
- [置顶] Effective STL 学习笔记
看Effective STL 作的一些笔记,希望对各位有帮助. 以下是50条条款及相关解释. 容器 1. 慎重选择容器类型,根据需要选择高效的容器类型. 2. 不要试图编写独立于容器类型的代码. 3. ...
- 《Effective STL》学习笔记
http://www.cnblogs.com/arthurliu/archive/2011/08/07/2108386.html 作者:咆哮的马甲 出处:http://www.cnblogs.com/ ...
- STL的erase()陷阱-迭代器失效总结
下面材料整理自Internet&著作. STL中的容器按存储方式分为两类,一类是按以数组形式存储的容器(如:vector .deque):另一类是以不连续的节点形式存储的容器(如:list.s ...
- stl vector、红黑树、set、multiset、map、multimap、迭代器失效、哈希表(hash_table)、hashset、hashmap、unordered_map、list
stl:即标准模板库,该库包含了诸多在计算机科学领域里所常用的基本数据结构和基本算法 六大组件: 容器.迭代器.算法.仿函数.空间配置器.迭代适配器 迭代器:迭代器(iterator)是一种抽象的设计 ...
- Effective STL 学习笔记 32 ~ 33
Effective STL 学习笔记 32 ~ 33 */--> div.org-src-container { font-size: 85%; font-family: monospace; ...
- Effective STL 学习笔记 31:排序算法
Effective STL 学习笔记 31:排序算法 */--> div.org-src-container { font-size: 85%; font-family: monospace; ...
- Effective STL 学习笔记 Item 26: Prefer Iterator to reverse_iterator and const_rever_itertor
Effective STL 学习笔记 Item 26: Prefer Iterator to reverse_iterator and const_rever_itertor */--> div ...
随机推荐
- python3-字典中存储列表
# Auther: Aaron Fan #示例1:#存储所点披萨的信息pizza = { '外皮':'厚的', '配料列表':['香菇', '奶酪'],}#概述所点的比萨print('您点了一道&qu ...
- unix 下 shell 遍历指定范围内的日期
UNIX下遍历日期,date 没有 -d 的参数,所以需要自己处理. 下面使用时差的方法进行计算,遍历的日期是降序的 #!/usr/bin/ksh . $HOME/.profile timelag= ...
- 自定义MVC的Helper扩展方法 转 Insus.NET
记得在开发ASP.NET时候,也经常性使用C#可以写自己义的扩展方法,如: http://www.cnblogs.com/insus/p/3154363.html 或http://www.cnblog ...
- 类的继承与super()的意义以即如何写一个正确的异常类
这些东西都是我看了许多名师课程和自己研究的成果,严禁转载,这里指出了如何正确的自己定义一个异常类并看一看sun写的java的源代码话题一:子类的构造器执行是否一定会伴随着父类的构造执行? 1.this ...
- Cactus在jexus上安装
在成功安装完Mono和jexus后(强烈建议Mono 4.2.1以上,jexus 5.6.1 以上,本人测试环境就是Mono 4.2.1和jexus 5.6.1) 第一步: 先配置jexus安装目录下 ...
- .NET 图片上传接收类
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...
- Django之博客系统:自定义认证
前面我们在登录的时候,是通过输入用户名和密码来进行认证 user=authenticate(username=cd['username'],password=cd['password']) 这个是通过 ...
- Java从入门到放弃——03.循环和判断
本文目标 选择结构:if,switch 循环结构:for , foreach ,while,do while 跳出语句:break,continue 1.选择结构 if: if(判断语句){ } s ...
- [SinGuLaRiTy] 数论题目复习
[SinGuLaRiTy-1020] Copyright (c) SinGuLaRiTy 2017. All Rights Reserved. [CQBZOJ 1464] Hankson 题目描述 H ...
- ios中的奇怪崩溃Signal和EXC_BAD_ACCESS错误分析
什么是Signal 在计算机科学中,信号(英语:Signals)是Unix.类Unix以及其他POSIX兼容的操作系统中进程间通讯的一种有限制的方式.它是一种异步的通知机制,用来提醒进程一个事件已经发 ...