一、序列式容器迭代器失效的场景
序列式容器以vector为例。分别有以下情况会失效:
1、push_back() 使迭代器失效。
在容器末尾添加一个元素。如果容器有剩余空间(capacity() > size()),则直接添加新元素到容器尾部。此时,原迭代器中end()会失效,其他的都不会失效。如果容器没有剩余空间(capacity() == size()),会导致容器重新分配内存,然后将数据从原内存复制到新内存,再在尾部添加新元素。此时,由于内存重新分配,原迭代器(所有)都失效。
2、pop_back() 使迭代器失效。
直接将容器中的最后一个元素删除,原迭代器中最后一个元素的迭代器和end()会失效,其余的都不会失效。
3、insert(iterator, n) 使迭代器失效。
如果容器有剩余空间,先在容器尾部插入一个元素,然后将插入点及之后的元素都向后移动一位,然后在插入点创建新元素。否则,会导致容器重新分配内存,接着将插入点之前的元素复制过去,在插入点创建新元素,再将插入点之后的元素复制过去。因此 ,如果没有内存的重新分配,原迭代器中插入点及插入点之后的迭代器(包括end())都失效。如果有内存的重新分配,原迭代器(所有)都失效。
4、erase(iterator) 使迭代器失效。
将删除点及之后的元素都向前移动一位,然后删除最后一个元素。因此,原迭代器中删除点之前的迭代器都有效,删除点之后的元素迭代器都失效。
二、关联式容器迭代器失效场景
set、multiset、map、multimap, 使用红黑树来存储数据。
1、insert(iterator) 插入不会使得任何迭代器失效;
2、删除运算使指向删除位置的迭代器失效,但是不会失效其他迭代器。erase迭代器只是被删元素的迭代器失效,返回值为被删除元素的下一个迭代器,所以要采用 iter=contan.erase(iter)和erase(iter++)的方式删除迭代器。erase(iter++)的删除方法对于内存连续的容器,例如vector不可用,因为被删除元素的下一个迭代器也失效了;iter=contan.erase(iter)则都可行。
三、防止因迭代器失效导致异常
1、删除多个元素方法:
for(vector<T>::iterator iter=veci.begin(); iter!=veci.end(); )
{
if(判断删除的元素的条件)
{
{//元素类型T为原始指针时
//T tmp = *iter;
//delete tmp;
}
iter = veci.erase(iter);
}
else
{
iter ++ ;
}
}
2、clear清除数据出现假删除
容器中的数据没了,容器中的内存还在,也就是clear可以清除数据使容器size变成0,但不会是容器容量capacity变成0。
clear只会清楚容器中的元素。若元素为指针,指针托管的堆内对象的内存需要手动清理。
//元素类型T为原始指针时
for(vector<T>::iterator iter=veci.begin(); iter!=veci.end(); )
{
T tmp = *iter;
delete tmp;
iter = veci.erase(iter);
}
//元素类型T为对象或一版类型时,智能指针类型为对象,而非真正的指针
for(vector<T>::iterator iter=veci.begin(); iter!=veci.end(); )
{
iter = veci.erase(iter);
}
//与clear等效
veci.clear();
有错误或不足欢迎评论指出!创作不易,转载请注明出处。如有帮助,记得点赞关注哦(⊙o⊙)
更多内容请关注个人博客:https://blog.csdn.net/qq_43148810