失效的三种情况
1、对于数组型容器(vector,deque)
- 插入删除操作都会使得操作元素后面的元素位置发生变化,因此指向操作位置及其后的元素的迭代器都会失效。即insert(*iter)或erase(*iter)后iter++是没有意义的。
- 解决办法:获取erase(*iter)返回的下一个有效迭代器 =>
iter = vec.erase(iter)
2、对于链表型容器(list)
- 插入不会使任何迭代器失效,删除只会使指向删除位置的迭代器失效,其他元素迭代器不受影响。
- 解决办法有两种:
- 获取erase(*iter)返回的下一个有效迭代器 =>
iter = vec.erase(iter)
erase(iter++)
- 获取erase(*iter)返回的下一个有效迭代器 =>
3、对于关联式容器(set,map,multiset,multimap)
- 插入不会使任何迭代器失效,删除只会使指向删除位置的迭代器失效,其他元素迭代器不受影响。
- 解决办法:和前面不同的是, 有的版本的stl-map中erase()没有返回值,比如SGI版,但vc版的有,因此这种情况下就只能采用
erase(iter++)
的方式
迭代器失效后不能参与任何运算,包括 iter++和 *iter
总结
类别 | 容器 | 插入 | 删除 |
---|---|---|---|
数组型容器 | vector,deque | 被操作元素及其后元素的迭代器都失效(若capacity发生改变则全部失效) | 被操作元素及其后元素的迭代器全部失效 |
链表型容器 | list | 所有迭代器不失效 | 有且仅有被删除元素的迭代器失效 |
关联式容器 | set,map, multiset,multimap | 所有迭代器不失效 | 有且仅有被删除元素的迭代器失效 |
迭代器失效后要重新获取新的有效的迭代器,这个迭代器是vector内存调整过后新的有效的迭代器,这样才能顺利执行后续操作。有两种解决方案:
//第一种、只要我们执行插入删除操作的时候,将下一个有效迭代器返回即可顺利执行后续操作
//不过注意有的版本(如SGI)的stl-map中insert和erase没有返回值,不能使用该方式
iter = vec.insert(iter);
iter = vec.erase(iter);
//第二种、数组型容器删除位置后的元素的迭代器都会失效,因此数组型容器不能采用这种方式
erase(iter++);//erase时递增当前iterator即可
*erase(iter++)
的执行过程分三步走:先把 iter传值到erase里面,然后 iter自增,再执行erase. 所以iter在失效前已经自增了。
讲解示例
为方便演示都只给出部分代码.
失效案例
while(iter != vec.end()) {
if (*iter == 0) vec.erase(iter);//该操作后当前iter迭代器就会失效
iter++;//再执行iter++,其行为是未定义的。
}
----------------------------------------------------------------
for (it = vec.begin(); it != vec.end(); it++) //后再执行it++就会报错
{
if (*it == 0) vec.erase(it);//此处会发生迭代器失效
}
数组型容器–解决失效 案例:数组型容器只能用第一种解决方案
while(iter != vec.end()){
if (*iter == 0) iter = vec.erase(iter);
//erase的返回值是删除元素下一个元素的迭代器,因此更新迭代器iter即可顺利执行后续操作
iter++;
}
关联型容器–解决失效 案例:这里采用的是第二种解决方案
while(iter != dmap.end()){
if (iter->first == 0) dmap.erase(iter++);
else iter++;
}