保護后臺登錄wordpress安卓優(yōu)化大師新版
【C++】 vector 迭代器失效問題
- 一. 迭代器失效問題分析
- 二. 對于vector可能會導致其迭代器失效的操作有:
- 1. 會引起其底層空間改變的操作,都有可能是迭代器失效
- 2. 指定位置元素的刪除操作--erase
- 3. Linux下,g++編譯器對迭代器失效的檢測并不是非常嚴格,處理也沒有vs下極端。
- 4. 與vector類似,string在 插入或 擴容操作 或 erase之后,迭代器也會失效
一. 迭代器失效問題分析
迭代器的主要作用就是讓算法能夠不用關心底層數(shù)據(jù)結構,其底層實際就是一個指針,或者是對指針進行了封裝,比如:vector的迭代器就是原生態(tài)指針T。因此迭代器失效,實際就是迭代器底層對應指針所指向的空間被銷毀了,而使用一塊已經被釋放的空間,造成的后果是程序崩潰(即如果繼續(xù)使用已經失效的迭代器, 程序可能會崩潰)。
注意1:迭代器失效后,代碼并不一定會崩潰,但是運行結果肯定不對,如果it不在begin和end范圍內,肯定會崩潰的。
注意2:vector使用動態(tài)分配數(shù)組來存儲它的元素。當新元素插入時候,這個數(shù)組需要被重新分配大小為了增加存儲空間。 “ 其做法是,分配一個新的數(shù)組,然后將全部元素移到這個數(shù)組 ”。 但是原來定義的的迭代器未作處理依舊指向原來的地址,這就是導致迭代器失效的原因。
也就是說:一旦擴容就會導致迭代器失效。
迭代器失效解決辦法:在使用前,對迭代器重新賦值即可
看圖分析: 一旦經過擴容后原來的迭代器指針 it 不可在用,因為它還指向原來的舊空間,舊空間會被釋放,舊空間釋放后 it 就會變?yōu)橐爸羔?#xff0c;需要重新更新迭代器即 newit
二. 對于vector可能會導致其迭代器失效的操作有:
1. 會引起其底層空間改變的操作,都有可能是迭代器失效
比如:resize、reserve、insert、assign、push_back等。
#include <iostream>
using namespace std;
#include <vector>
int main()
{vector<int> v{ 1,2,3,4,5,6 };auto it = v.begin();// 將有效元素個數(shù)增加到100個,多出的位置使用8填充,操作期間底層會擴容// v.resize(100, 8);// 插入元素期間,可能會引起擴容,而導致原空間被釋放// v.insert(v.begin(), 0);// // v.push_back(8);// 給vector重新賦值,可能會引起底層容量改變v.assign(100, 8);while (it != v.end()){cout << *it << " ";++it;}cout << endl;return 0;
}
出錯原因:以上操作,都有可能會導致vector擴容,也就是說vector底層原理舊空間被釋放掉,而在打印時,it還使用的是釋放之間的舊空間,在對it迭代器操作時,實際操作的是一塊已經被釋放的空間,而引起代碼運行時崩潰。
解決方式:在以上操作完成之后,如果想要繼續(xù)通過迭代器操作vector中的元素,只需給it重新賦值即可。
2. 指定位置元素的刪除操作–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(第一個)所在位置的iteratorvector<int>::iterator pos = find(v.begin(), v.end(), 3);// 刪除pos位置的數(shù)據(jù),導致pos迭代器失效。v.erase(pos);cout << *pos << endl; // 此處會導致非法訪問return 0;
}
erase刪除pos位置元素后,pos位置之后的元素會往前搬移,沒有導致底層空間的改變,理論上講迭代器不應該會失效,但是:如果pos剛好是最后一個元素,刪完之后pos剛好是end的位置,而end位置是沒有元素的,那么pos就失效了。因此刪除vector中任意位置上元素時,vs編譯器就認為該位置迭代器失效了。
3. Linux下,g++編譯器對迭代器失效的檢測并不是非常嚴格,處理也沒有vs下極端。
#include <iostream>
using namespace std;
#include <vector>
// 1. 擴容之后,迭代器已經失效了,程序雖然可以運行,但是運行結果已經不對了
int main()
{vector<int> v{ 1,2,3,4,5 };for (size_t i = 0; i < v.size(); ++i)cout << v[i] << " ";cout << endl;auto it = v.begin();cout << "擴容之前,vector的容量為: " << v.capacity() << endl;// 通過reserve將底層空間設置為100,目的是為了讓vector的迭代器失效 v.reserve(100);cout << "擴容之后,vector的容量為: " << v.capacity() << endl;// 經過上述reserve之后,it迭代器肯定會失效,在vs下程序就直接崩潰了,但是linux下不會// 雖然可能運行,但是輸出的結果是不對的while (it != v.end()){cout << *it << " ";++it;}cout << endl;return 0;
}