总结:顺序迭代器失效的范围

向容器中添加元素或删除元素会导致指向容器元素的迭代器、指针或引用失效。

一个失效的迭代器、引用、或指针不再指向任何元素。

向容器中添加元素insert

  • vector和string:

1、如果插入元素之后,容器的大小(size())超过了容器的预分配空间(即capacity()属性),容器的存储空间需要重新分配,则指向元素的迭代器、指针和引用都失效;(关于capacity和size的区别在之前的blog有提到)
2、如果插入元素并没有导致存储空间重新分配,则插入元素之前的迭代器、指针和引用依旧有效;当前插入元素以及插入元素位置之后的迭代器、指针和引用都失效。

vector和string是一个顺序容器,在内存中是一块连续的内存空间,当删除或插入一个元素时,内存中的元素会发生移动,以保持空间的连续性;所以在插入删除操作之后,其他元素的地址发生了变化,之前获取的迭代器根据原有的信息就访问不到正确的数据。
还存在capacity < size的情况,这时候需要分配新的空间来保存已有元素和新元素,将已有元素移动到新的空间,然后添加新元素,释放旧的存储空间,理所当然之前的所有迭代器都失效了。

  • deque

1、插入到首尾位置之外的任何元素,都会导致迭代器失效;

2、插入到首尾位置时,指向容器元素的迭代器会失效,但是指向元素的引用和指针不会失效。

  • list和forward_list

1、无论插入到什么位置,迭代器仍然有效

从容器中删除元素erase

  • vector和string

1、指向删除元素之前的迭代器依旧有效;指向删除元素之后的迭代器失效;

  • deque

1、在首位置删除元素,迭代器都不会失效;

2、在尾位置删除元素,尾后迭代器失效,其他迭代器不会失效;

3、在除了首尾位置之外删除元素,所有迭代器都会失效。

deque容器迭代器失效的特殊性和deque的结构有关系;
因为:deque是一个队列,队列在首尾位置删除或插入元素的时候,是通过头指针和尾指针不断移动,实现元素的查找并进行相应操作的的。在这期间,元素并没有发生移动,只是头、尾指针不断在移动。所以在头位置删除元素后,并不会改变其他位置的迭代器;在尾位置删除元素后,只会使尾后迭代器失效,因为尾指针向前移动了一个位置,尾后迭代器改变了位置。
而在其他位置进行插入或删除操作时,必然会造成元素的移动;其实,在队列的操作中,并不允许在中间位置进行相关操作的,这不符合队列(FIFO)的特性,所以迭代器都会失效;

  • list和forward_list

借用STL迭代器失效

结论:在STL里,我们不能以指针来看待迭代器,指针是与内存绑定的,而迭代器是与容器里的元素绑定的,删除了之后,该迭代器就失效了,在对其重新赋值之前,不能再访问此迭代器。


避免迭代器失效的方法

1、在循环体内,保证每个循环步都更新迭代器

推荐使用insert和erase来插入和删除元素。因此它们返回指向元素的迭代器,在进行这两个操作时,更新迭代器;

vector<int> v={0,1,2,3,4,5,6,7,8,9};
     auto iter=v.begin();
     while(iter != v.end())
     {
         if(*iter % 2 !=0)
         {
             iter=v.insert(iter,*iter++);//使用insert的返回值更新iter
             iter++;
         }
         else{
          iter=v.erase(iter);   //使用erase的返回值更新iter
         }
     }
2、不要保存end()尾后迭代器
vector <int> v={1,2,3,4,5,6,7,8};
auto iter=v.begin();
auto end=v.end();
int i=0;
while(iter != end)
{
    v.push_back(i++);
}

上面的例子就是一个错误的典型,在循环体外end保存了容器的尾后迭代器,但在循环体内部插入了元素,尾后迭代器失效了,end也就不再指向容器中的任何元素了。

因此,在使用end()尾后迭代器的时候,必须在循环体内部,反复调用end(),不能在循环体外面保存尾后迭代器。


本文参考了:
http://www.jb51.net/article/100683.htm
http://blog.csdn.net/lujiandong1/article/details/49872763
http://www.cnblogs.com/qiaoconglovelife/p/5370396.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值