迭代器失效的几种情况,以vector类为例
1. 操作已经释放的空间
我们先来看一段代码
这段代码乍一看好像是没有什么问题,输出第一个元素的值,那结果是不是我们想的那样?
通过结果我们可以看出,第一次打印没有出错,但是第二次打印却报错,是为什么?
我们第一次打印完后,进行扩容,向系统申请一块更大的空间,会将原来空间的数据拷贝到新开辟的空间,最后会将原来的空间释放。但此时it指向的是原有空间,原有空间释放,it就会成为野指针。第二次打印,对it作解引用,访问已经释放的空间,程序就会崩溃并且也不安全。
只要涉及到扩容,会开辟新的空间,就会产生迭代器失效的问题。涉及到扩容的函数有:resize、reverse、insert、push_back、assign等。
解决方法:重新获取迭代器
我们可以通过重新获取迭代器的方法,解决迭代器失效的问题。
2. 迭代器指向发生了错位
vector容器中,删除一个元素,后面的元素都会向前移动一个位置,此时迭代器与原来的指向发生了变化,迭代器就会失效。
我们再来看一段代码:
上面代码进行头删之后,迭代器虽然指向发生了变化,但是迭代器指向的也是一个有效元素,但为什么会失效呢?
如果要删除的pos是最后一个有效元素,删完之后,pos就会指向一个没有元素的位置,此时对pos进行操作,编译器就会报错。因此删除vector中任意位置上元素时,vs就认为该位置迭代器失效了。
但是在Linux中,使用erase,迭代器不会失效。
解决方法
iterator erase (iterator position);
erase返回值是一个迭代器,迭代器指向删除之后的下一个位置
我们只需要重新获取erase的返回值,就可以解决。
举例
删除vector中的所有偶数。
void test()
{
int arr[] = { 1, 2, 3, 4, 7, 8, 12 };
vector<int> v(arr, arr + sizeof(arr) / sizeof(arr[0]));
vector<int>::iterator it = v.begin();
while (it != v.end())
{
if (*it % 2 == 0)
it = v.erase(it);//如果是偶数就直接删除,获取erase返回值
else
it++;//如果不是偶数,迭代器继续向前移动
}
}
迭代器失效解决办法:在使用前,对迭代器重新赋值即可。