迭代器本质一个指针,或者就是对指针进行封装,那么所谓的迭代器失效也就是指针失效
指针失效:指针所指向的空间被销毁了,或者该指针成为一个野指针。
访问一个已经被释放了的空间,造成程序崩溃。
对于vector来说可能造成的迭代器失效问题:
一、所有会引起底层空间改变的操作,都有可能造成迭代器失效
resize、reverse、insert、push_back、assign
以下代码正常运行:依次打印v的各个元素
vector<int> v{ 0,1,2,3,4,5,6,7,8,9 };
auto it = v.begin();
while (it != v.end())
{
cout << *it << " ";
++it;
}
cout << endl;
①以下操作均有可能引起程序崩溃:
vector<int> v{ 0,1,2,3,4,5,6,7,8,9 };
auto it = v.begin();
v.resize(20, 1); // 改变v的容量大于size()的用1来填充
v.reserve(20); // 改变v的容量
v.insert(v.begin(), 20, 1); // 0号下标后插入20个1
v.push_back(0); //插入元素,可能会引起扩容,而导致原空间被释放
v.assign(100, 8); // 给vector重新赋值,可能会引起底层容量改变
while (it != v.end())
{
cout << *it << " ";
++it;
}
cout << endl;
对于insert()接口:
原因:
扩容的本质:开辟新空间、拷贝旧元素、释放旧空间、使用新空间
那么在这个过程中,之前的旧空间已经被释放掉了,然而在后续打印的时候it仍然指向的是原来的已经被释放掉了的旧空间,对已经释放的旧空间进行操作,引起程序崩溃。
预防:
在释放旧空间之后,对it迭代器进行更新。
如下:代码正常执行。
v.assign(100, 8); // 给vector重新赋值,可能会引起底层容量改变
it = v.begin();
while (it != v.end())
{
cout << *it << " ";
++it;
}
cout << endl;
二、使用erase()接口
iterator erase(iterator position); //删除指定位置元素
iterator erase(iterator first, iterator last);//删除指定区间元素
删除begin()位置的元素,但是之前用it迭代器指向的就是begin()位置元素,删除之后,it指向了一块已经被释放了的空间,再次进行打印操作时就会发生程序崩溃。
vector<int> v{ 0,1,2,3,4,5,6,7,8,9 };
auto it = v.begin();
v.erase(v.begin());
while (it != v.end())
{
cout << *it << " ";
++it;
}
cout << endl;
vector的删除操作不光会导致指向被删除元素的迭代器失效,删除元素后面的迭代器也会失效
解决:
删除的时候使用it来进行接受,也就是对it进行重新赋值。
it = v.erase(v.begin());
继续了解一下erase()
以下代码的功能是删除vector中所有的偶数
#include <iostream>
using namespace std;
#include <vector>
int main()
{
vector<int> v{ 1, 2, 3, 4, 2, 2, 6, 2, 7};
auto it = v.begin();
while (it != v.end())
{
if (*it % 2 == 0)
it = v.erase(it);
else
++it;
}
return 0;
}
我们发现:每当执行一次it = v.erase(it);操作,it就会指向被删除的元素的下一个元素位置。