所谓迭代器失效就是原有的空间被销毁,而继续用迭代器来进行访问,导致程序崩溃。
我们以vector为例来讲解迭代器失效问题
增加元素
对于原有的空间被销毁,除了主动释放,那就只有扩容的时候才可能发生的事。
扩容的时候,会释放原有的空间,并且会开辟新空间,并把原有空间里的数据拷贝到新空间里面去,此时,迭代器对应的指针所指向的空间不再属于自己的,造成经典的野指针问题。
那么这一类问题怎么解决呢?
只需要把迭代器对应的指针重新赋值就行:
#include<iostream>
#include<vector>
using namespace std;
int main()
{
int a[] = { 0,1,2,3,4,5,6,7,8,9 };
int sz = sizeof(a) / sizeof(a[0]);
vector<int> v(a,a + sz);
vector<int>::iterator it = v.begin();
v.push_back(10);
it = v.begin();//扩容之后迭代器就要重新赋值,如果没有,就报错
while (it != v.end())
{
cout << *it << " ";
++it;
}
return 0;
}
如果上面这段代码不能很好的展现,还有下面这段:
int main()
{
int a[] = { 1,2,3,4,5,6,7,8,9 };
int sz = sizeof(a) / sizeof(a[0]);
vector<int> v(a, a + sz);
vector<int>::iterator pos = find(v.begin(), v.end(), 3);
//v.insert(pos, 30);//如果用这行代码,不用下面这行代码,也会导致野指针问题,因为pos位置没有更新
pos = v.insert(pos, 30);
vector<int>::iterator it = v.begin();
while (it != v.end())
{
cout << *it << " ";
++it;
}
cout << endl;
(*pos)++;
for (auto ch : v)
{
cout << ch << " ";
}
cout << endl;
return 0;
}
删除元素
当然,并不是只有释放原有空间开辟新空间才会出现迭代器失效问题,删除数据也会,有朋友可能会想了:删除怎么可能会造成迭代器失效,又没有销毁空间?
删除前面几个还好,如果删除的是最后一个呢?
如果仅仅只是删除8那还没事,可是如果还要对pos位置进行操作的话就出问题了,这也是一个野指针问题,所以删除之后迭代器还是要更新的。
接下来看看这段代码:
int main()
{
int a[] = { 1,2,3,4 };
int sz = sizeof(a) / sizeof(a[0]);
vector<int> v(a, a + sz);
//删除所以偶数
vector<int>::iterator pos = v.begin();
while (pos != v.end())
{
if (*pos % 2 == 0)
{
v.erase(pos);
}
pos++;
}
for (auto ch : v)
{
cout << ch << " ";
}
cout << endl;
return 0;
}
这段代码是有问题的,问题出在哪呢?
首先删除之前是这个样子的,但是代码中,无论是否遇到偶数,都会++,所以会导致下面这张图的局面:
这个时候就已经开始出现问题,换一种情况,如果是连续的偶数,那就会发生跳过,导致后面那个偶数没有被删除。
后面还有更严重的:
此时pos指向的数据是4,要先删除:
再++:
此时,它们就已经错过了,再来看这个循环结束条件,是!=,所以造成死循环。
怎么改进呢?
其实只需要解决删除数据后pos位置的更新就行:
int main()
{
int a[] = { 1,2,3,4 };
int sz = sizeof(a) / sizeof(a[0]);
vector<int> v(a, a + sz);
//删除所以偶数
vector<int>::iterator pos = v.begin();
/*while (pos != v.end())
{
if (*pos % 2 == 0)
{
v.erase(pos);
}
pos++;
}*/
while (pos != v.end())
{
if (*pos % 2 == 0)
{
pos = v.erase(pos);
}
else
{
pos++;
}
}
for (auto ch : v)
{
cout << ch << " ";
}
cout << endl;
return 0;
}
所以,我们在用迭代器的时候如果进行了增加删除的操作,还是要把迭代器更新一下。