C++ 迭代器失效問題解決
1.vector迭代器失效問題
迭代器的主要作用就是讓算法能夠不用關(guān)心底層數(shù)據(jù)結(jié)構(gòu),其底層實(shí)際就是一個(gè)指針,或者是對(duì)指針進(jìn)行了封裝 ,比如: vector 的迭代器就是原生態(tài)指針 T* 。因此 迭代器失效,實(shí)際就是迭代器底層對(duì)應(yīng)指針?biāo)赶虻?/strong> 空間被銷毀了,而使用一塊已經(jīng)被釋放的空間 ,造成的后果是程序崩潰 ( 即 如果繼續(xù)使用已經(jīng)失效的迭代器, 程序可能會(huì)崩潰 ) 。
在C++中,當(dāng)一個(gè)vector進(jìn)行了插入或刪除操作時(shí),其迭代器可能會(huì)失效。這是因?yàn)樵诓迦牖騽h除操作之后,vector可能會(huì)重新分配內(nèi)存空間,導(dǎo)致原來的迭代器指向的位置不再有效。
可能會(huì)導(dǎo)致其迭代器失效的操作有
1.底層空間改變
1. 會(huì)引起其底層空間改變的操作,都有可能是迭代器失效 ,比如: resize 、 reserve 、 insert 、 assign 、push_back等。
#define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std; #include<vector> int main() { vector<int> v; v = { 1,2,3,4,5,6 }; auto it = v.begin(); //使用reserve擴(kuò)容,可能會(huì)引起底層容量的改變,舊空間釋放,但是it依舊使用的時(shí)釋放前的舊空間 v.reserve(100); while (it != v.end()) { cout << *it << " "; ++it; } return 0; }
我們使用resize 、 reserve 、 insert 、 assign、 push_back等操作都可能會(huì)導(dǎo)致擴(kuò)容, 也就是說vector底層原理舊空間被釋放掉, 而在打印時(shí),it還使用的是釋放之間的舊空間,在對(duì)it迭代器操作時(shí),實(shí)際操作的是一塊已經(jīng)被釋放的 空間,而引起代碼運(yùn)行時(shí)崩潰。
如果我們?cè)跀U(kuò)容后重新賦值即可解決這個(gè)問題,可以繼續(xù)操作it迭代器。
2.指定位置元素的刪除操作
#define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std; #include<vector> int main() { vector<int> v; v = { 1,2,3,4,5,6 }; //auto it = v.begin(); //使用reserve擴(kuò)容,可能會(huì)引起底層容量的改變,舊空間釋放,但是it依舊使用的時(shí)釋放前的舊空間 //v.reserve(100); auto it = v.begin(); while (it != v.end()) { v.erase(it); //刪除it位置的數(shù)據(jù),導(dǎo)致迭代器失效 //這時(shí)再對(duì)it進(jìn)行操作就是非法訪問 cout << *it << endl; ++it; } return 0; }
如圖中代碼,運(yùn)行會(huì)崩潰
erase 刪除 pos 位置元素后, pos 位置之后的元素會(huì)往前搬移,沒有導(dǎo)致底層空間的改變,理論上講迭代器不應(yīng)該會(huì)失效,但是:如果pos 剛好是最后一個(gè)元素,刪完之后 pos 剛好是 end 的位置,而 end 位置是沒有元素的,那么pos 就失效了。因此刪除 vector 中任意位置上元素時(shí), vs 就認(rèn)為該位置迭代器失效了。
如果在刪除后對(duì)迭代器it重新賦值,這個(gè)時(shí)候就不會(huì)失效,因?yàn)閑rase返回刪除元素下一個(gè)位置元素的迭代器。
2.Linux下的迭代器失效檢測(cè)
Linux 下, g++ 編譯器對(duì)迭代器失效的檢測(cè)并不是非常嚴(yán)格,處理也沒有 vs 下極端。
1.擴(kuò)容
運(yùn)行如下代碼:
可以運(yùn)行但是結(jié)果已經(jīng)出錯(cuò)。
2.刪除
運(yùn)行如下代碼
可以正常運(yùn)行,erase刪除任意位置代碼后,linux下迭代器并沒有失效 因?yàn)榭臻g還是原來的空間,后序元素往前搬移了,it的位置還是有效的
但是如果刪除的是最后一個(gè)元素呢
程序崩潰,因?yàn)閯h除最后一個(gè)元素,刪除后it已經(jīng)超過end,++it導(dǎo)致程序崩潰
3.解決方法
與 vector 類似, string 在插入 + 擴(kuò)容操作 +erase 之后,迭代器也會(huì)失效
迭代器失效解決辦法:在使用前,對(duì)迭代器重新賦值即可
1.在進(jìn)行插入或刪除操作之后,更新迭代器的位置,使其指向有效的元素。
2.在進(jìn)行插入或刪除操作之前,先將迭代器保存下來,然后再進(jìn)行操作之后重新定位迭代器。
3.另外,C++11引入了emplace_back()和emplace()函數(shù),它們可以在vector中直接構(gòu)造對(duì)象,而不是先創(chuàng)建臨時(shí)對(duì)象再插入,這樣可以減少迭代器失效的可能性
到此這篇關(guān)于C++ 迭代器失效問題解決的文章就介紹到這了,更多相關(guān)C++ 迭代器失效內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于win32 gettimeofday替代方案
下面小編就為大家?guī)硪黄P(guān)于win32 gettimeofday替代方案。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-12-12C++類繼承 繼承后函數(shù)的值實(shí)現(xiàn)詳解
這篇文章主要介紹了C++類繼承 繼承后函數(shù)的值實(shí)現(xiàn)詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09java 中ArrayList與LinkedList性能比較
這篇文章主要介紹了java 中ArrayList與LinkedList性能比較的相關(guān)資料,需要的朋友可以參考下2017-03-03