什么是迭代器失效?
我们在使用STL时,有时候会出现程序崩溃的结果,而原因如图所示,这便是迭代器失效所导致的
哪些操作会引起迭代器失效呢?
- 由于插入元素,或者扩容可能引起的迭代器指向的元素或者空间发生变化,从而导致迭代器失效
- 由于删除元素使得某些元素次序发生变化使得原本指向某元素的迭代器不再指向希望指向的元素。
- 由于容器空间被释放导致存放原容器元素的空间不再有效,从而使得指向原空间的迭代器失效。
- 由于容器元素整体“迁移”导致存放原容器元素的空间不再有效,从而使得指向原空间的迭代器失效。
迭代器失效:vector容器
-
由于插入元素可能引起的迭代器指向的元素或者空间发生变化,从而导致迭代器失效
-
接口:insert,resize,reserve,push_back,assign
insert和push_back操作:
void Test1()
{
vector<int> v = { 1, 2, 3 };
vector<int>::iterator it = v.begin();
v.insert(v.begin(), 0);
while (it != v.end())
{
cout << *it << endl;
++it;
}
cout << endl;
}
void Test2()
{
vector<int> v = { 1, 2, 3 };
vector<int>::iterator it = v.end();
v.push_back(4);
cout << *it << endl;
}
同样push_back操作也会引起同样的问题 ,但是这样迭代器失效似乎存在一种偶然情况,我们不得不思考一下,在insert操作的时候我们在it指向的元素后面进行插入,在push_back操作的时候,我们也在it指向的元素后面进行操作,迭代器是否会失效,然而经过验证,即使这样操作,迭代器依旧会失效,代码如下: (这好像是一种保护机制,经验证并非是空间变换所导致的)
void Test1()
{
vector<int> v = { 1, 2, 3 };
vector<int>::iterator it = v.begin();
v.insert(v.begin()+1, 0);
while (it != v.end())
{
cout << *it << endl;
++it;
}
cout << endl;
}
void Test2()
{
vector<int> v = { 1, 2, 3 };
vector<int>::iterator it = v.begin();
v.push_back(4);
cout << *it << endl;
}
我们可以再次思考,insert、push_back、resize、reserve等都可以扩展空间,倘若在原空间基础上无法进行扩展,做法是重新寻找一个足够大小的空间,将原来的元素拷贝到新空间上,如果我们在使用指向旧空间的迭代器,自然而然的就会发生错误,这也是我们上面提到的由于插入元素,或者扩容可能引起的迭代器指向的空间发生变化,从而导致迭代器失效
-
由于删除元素使得某些元素次序发生变化使得原本指向某元素的迭代器不再指向希望指向的元素。
-
接口:erase、pop_back
-
由于容器空间被释放导致存放原容器元素的空间不再有效,从而使得指向原空间的迭代器失效。 接口clear
-
由于容器元素整体“迁移”导致存放原容器元素的空间不再有效,从而使得指向原空间的迭代器失效。 接口swap
解决迭代器失效的方法
解决迭代器失效最有效直接的方法就是在进行任何可能导致迭代器失效的操作之后,重新获取迭代器
总结:
-
对于连续型空间存储结构的容器 ,如vector:
插入或者扩容操作会导致所有迭代器失效(原有空间不足,vector必须重新分配存储空间,用来存放原来的元素以及新添加的元素:存放在旧存储空间的元素被复制到新的存储空间里,接着插入新的元素,最后撤销旧的存储空间。这种情况发生,一定会导致vector容器的所有迭代器都失效。)
erase删除操作,会导致删除位置以后的元素发生搬移,必定导致从删除位置开始以后的迭代器全部失效
clear清空操作,swap交换操作,必定导致vector容器的所有迭代器失效
-
对于非连续型空间存储结构的容器,如list、map、set等等:
erase删除操作,仅仅会导致删除位置的迭代器失效(并为发生元素迁移,并且删除该结点时,对应的空间被释放)
clear清空操作,swap交换操作,必定导致容器的所有迭代器失效