vector的迭代器失效问题
迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了封装,比如:vector的迭代器就是原生态指针T*。
因此迭代器失效,实际就是迭代器底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间,造成的后果是程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)。
1.引起底层空间改变的操作
例如:resize
、reserve
、insert
、assign
、push_back
等。
来看代码:
(编译器:VS2013)
#include <iostream>
using namespace std;
#include <vector>
int main()
{
vector<int> v{ 1, 2, 3, 4, 5, 6 };
auto it = v.begin();
//1.resize:将有效元素增加到20个,多的位置用10填充,操作时底层会扩容
v.resize(20, 10);
//2.reserve:改变扩容大小,不改变有效元素个数,操作时底层容量可能改变
v.reserve(100);
//3.insert/push_bcak:插入元素时,可能会引起扩容,导致原来的空间被释放
v.insert(v.begin(), 0);
v.push_back(7);
//4.assign:给Vector重新赋值,可能引起底层容量改变
v.assign(100, 8);
while (it != v.end())
{
cout << *it << " ";
++it;
}
cout << endl;
return 0;
}
- resize:将有效元素增加到20个,多的位置用10填充,操作时底层会扩容
- reserve:改变扩容大小,不改变有效元素个数,操作时底层容量可能改变
- insert/push_bcak:插入元素时,可能会引起扩容,导致原来的空间被释放
- assign:给Vector重新赋值,可能引起底层容量改变
运行结果:
出错原因:
以上操作,都有可能会导致vector扩容,在底层中,创建新的空间,旧空间被释放掉,而在打印时,it还使用的是释放之后的旧空间,在对it迭代器操作时,实际操作的是一块已经被释放的空间,而引起代码运行时崩溃。
2.指定位置元素的删除操作
例如:erase
来看代码:
(编译器:VS2013)
#include <iostream>
using namespace std;
#include <vector>
int main()
{
vector<int> v{ 1, 2, 3, 4 };
auto it = v.begin();
while (it != v.end())
{
if (*it % 2 == 0)
{
v.erase(it);
++it;
}
}
return 0;
}
出错原因:
这段代码的作用是删除所有偶数。
erase删除2这个元素后,2位置之后的元素会往前搬移,没有导致底层空间的改变,理论上讲迭代器不应该会失效。
但是,当删除最后一个元素偶数4时,删完之后,后面的位置是没有元素的,那么迭代器就失效了。
因此删除vector中任意位置上元素时,vs就认为该位置迭代器失效了。
3.解决办法
在使用之前对迭代器重新赋值
#include <iostream>
using namespace std;
#include <vector>
int main()
{
vector<int> v{ 1, 2, 3,4,5 };
auto it = v.begin();
while (it != v.end())
{
if (*it % 2 == 0)
{
it = v.erase(it);
}
else
{
++it;
}
}
return 0;
}
#include <iostream>
using namespace std;
#include <vector>
int main()
{
vector<int> v{ 1, 2, 3, 4, 5, 6 };
auto it = v.begin();
it=v.insert(v.begin(), 0);
while (it != v.end())
{
cout << *it << " ";
++it;
}
cout << endl;
return 0;
}