【C++】STL的迭代器失效问题
STL容器的迭代器失效问题
迭代器的作用就是让算法能够不用关心底层数据结构,其底层其实就是指针或者对指针进行封装,比如vector和string的迭代器就是原生态指针T*。因此迭代器失效就是迭代器底层对应执政指向的空间被销毁了,而使用一块已经被释放的空间,可能就会造成程序崩溃。
可能会造成迭代器失效的操作
会引起底层空间改变的操作,都可能会迭代器失效
比如:resize() reserve() insert() push_back() 等
#include <iostream> using namespace std; #include <vector> int main() { vector<int> v{ 1,2,3,4,5,6 }; auto it = v.begin(); // 将有效元素个数增加到100个,多出的位置使用8填充,操作期间底层会扩容 v.resize(100, 8); // reserve的作用就是改变扩容大小但不改变有效元素个数,操作期间可能会引起底层容量改变 v.reserve(100); //插入元素期间,可能会引起扩容,而导致原空间被释放 v.insert(v.begin(), 0); v.push_back(8); while (it != v.end()) { cout << *it << " "; ++it; } cout << endl; return 0; }
如果进行以上操作,就有可能会出现空间扩容,也就是原来的空间被释放掉,数据被拷贝到了新空间,但是迭代器依旧指向的是旧空间,此时对迭代器进行操作,就会访问到已经释放的空间,所以会出现迭代器失效的报错。
指定位置元素的删除操作
erase操作也会造成迭代器失效
erase删除pos位置元素之后,pos位置之后的元素会往前挪,并不会导致底层空间的改变,理论上不会造成迭代器失效,但是当删除元素之后,当前迭代器就会指向下一个元素的位置,如果刚好删除的是最后一个位置的元素,那么当前位置迭代器就会指向下一个位置,而下一个位置是没有元素的,那么pos就会失效。所以编译器为erase做了优化,删除元素时,就会认为该位置迭代器失效。用老一点版本的编译器有可能不会优化,删除操作可能不会造成迭代器失效。
#include <iostream> using namespace std; #include <vector> int main() { int a[] = { 1, 2, 3, 4 }; vector<int> v(a, a + sizeof(a) / sizeof(int)); // 使用find查找3所在位置的iterator vector<int>::iterator pos = find(v.begin(), v.end(), 3); // 删除pos位置的数据,导致pos迭代器失效。 v.erase(pos); cout << *pos << endl; // 此处会导致非法访问 return 0; }
迭代器失效的解决办法
既然在进行上面的那些操作之后,迭代器的位置依旧指向旧空间。那么我们在访问迭代器之前,对它重新进行赋值,也就是更新迭代器指向的位置。那么我们再次使用就不会造成访问到非法位置的情况,迭代器失效的问题就不会出现。
#include <iostream> using namespace std; #include <vector> int main() { vector<int> v{ 1,2,3,4,5,6 }; auto it = v.begin(); v.resize(100, 8); v.reserve(100); v.insert(v.begin(), 0); v.push_back(8); v.erase(v.begin()); //更新迭代器 it = v.begin(); while (it != v.end()) { cout << *it << " "; ++it; } cout << endl; return 0; }
下一篇:
Python面向对象习题练习(继承)