容器操作可能使迭代器失效
向容器中添加元素和从容器中删除元素的操作可能会使指向容器元素的指针、引用或迭代器失效。一个失效的指针、引用或迭代器不再表示任何元素。使用失效的指针、引用或迭代器是一种严重的程序设计错误,很可能引起与使用未初始化指针一样的问题。
向容器添加元素后:
- 如果容器是vector或string,且存储空间重新分配,则指向容器的迭代器、指针和引用都会失效。如果存储空间未重新分配,指向插入位置之前的元素的迭代器、指针和引用仍有效,但指向插入位置之后的元素的迭代器、指针和引用将会失效。
//初始化两个容器,定义两个迭代器并输出结果
vector<int> v(1,1);
string s{ "abc" };
auto it = v.begin();
auto sit = s.begin();
cout << *it << ' ' << *sit << ' ' << endl;
正常输出迭代器指向的内容
向容器中插入元素导致存储空间重新分配
//插入元素后容器的存储空间重新分配
v.push_back(2);
s = 'a' + s;
cout << *it <<' ' << *sit << ' ';//运行到此处报错
在调试窗口中可以看到vector的迭代器直接就乱七八糟了,string的迭代器的值看似没错,但是当输出它时,报错提示指向string的迭代器已经失效了
- 对于deque,插入到除首尾位置之外的任何位置都会导致迭代器、指针和引用失效。如果在首尾位置添加元素,迭代器会失效,但指向存在的元素的引用和指针不会失效。
deque<int> s{ 1,2,3 };
auto it = s.begin();
int& r = s[2];
s.push_back(4);//在尾部插入元素
cout << r << *it;//it已经失效,会报错
在尾部插入元素后,it已经失效,对deque内元素的引用仍然有效
- 对于list和forward_list,指向容器的迭代器(包括尾后迭代器和首前迭代器)、指针和引用仍有效。
list<int> l(1, 1);
auto it = l.begin();
l.push_back(2);
cout << *it;
插入新元素后,迭代器仍有效
从容器中删除元素后
首先,被删除元素的迭代器、指针和引用失效,因为该元素已经被销毁了,而对于其他元素,当我们删除一个元素后:
- 对于list和forward_list,指向容器其他位置的迭代器(包括尾后迭代器和首前迭代器)、引用和指针扔有效
list<int> l{ 1,2,3,4,5 };
auto it = l.begin();
auto del = ++l.begin();//del指向被删除的元素
l.erase(del);
cout << *it;
删除指定元素后,该元素的迭代器失效,其他元素的迭代器仍有效
- 对于deque,如果在首尾外的任何位置删除元素,那么其他元素的迭代器、指针引用也将失效。删除deque的尾元素,则尾后迭代器失效,其他不受影响;删除首元素,其他也不受影响。
首先删除除首尾元素外的任意元素
deque<int> l{ 1,2,3,4,5 };
auto it = l.begin();
auto del = ++l.begin();
l.erase(del);//删除了中间的某个元素
cout << *it;
迭代器it也失效了
删除首元素
auto it = ++l.begin();
auto del = l.begin();
l.erase(del);//删除首元素
删除首元素后其他元素的迭代器依旧有效
删除尾元素
auto it = l.end();
auto temp = ++l.begin();
auto del = l.end()-1;
l.erase(del);//删除首元素
删除尾元素后,尾后迭代器也失效了
- 对于vector和string,指向被删除元素之前元素的迭代器、引用和指针仍有效。当删除元素时,尾后迭代器总会失效
vector<int> v{ 1,2,3,4,5 };
auto it = v.end()-1;
auto temp = v.begin();
auto del = temp+1;
l.erase(del);//删除首元素
cout << *it << ' ';//报错,删除元素后的迭代器已失效
cout << *temp << ' ';//删除元素前的迭代器有效,正常输出