在使用std的容器的時(shí)候,不少人喜歡用vector, 因?yàn)楸绕?span lang="EN-US">list,更省空間,而且可以根據(jù)index直接讀取某個(gè)值,而不用一個(gè)個(gè)枚舉來(lái)取.
但是,std::vector確實(shí)有一些值得注意的陷阱, 這里先說(shuō)其中一個(gè), 請(qǐng)看以下代碼.
std::vector< int > values;
values.push_back(1);
values.push_back(2);
values.push_back(3);
values.erase(values.begin() + 1);
乍看之下,這幾行簡(jiǎn)單的代碼沒(méi)什么 問(wèn)題. 實(shí)際執(zhí)行起來(lái), 還是沒(méi)什么問(wèn)題 , 但卻有一個(gè)陷阱. 由于例子里面用的是int的vector,所以這樣做沒(méi)有任何問(wèn)題, 但,假如不是一個(gè)int, 而是一個(gè)類,一個(gè)結(jié)構(gòu)體,類或結(jié)構(gòu)體里面還有指針, 那就很可能出問(wèn)題了. why?
因?yàn)?span lang="EN-US">vector不象list,vector始終要保持一個(gè)完整的內(nèi)存結(jié)構(gòu)(因?yàn)榫褪且粋€(gè)數(shù)組),這樣才可以讓values[1]這樣的方式正確運(yùn)行. 但是,如果要在vector中間刪掉一個(gè)成員的話,vector是這樣做的, 先把該成員后面的一個(gè)成員,一直到最后一個(gè)成員往前一位置拷貝,這樣需要?jiǎng)h除的成員已經(jīng)被后面的覆蓋了, 然后再刪除最后一個(gè)成員,這樣,vector又能保持一段完整的內(nèi)存結(jié)構(gòu)了. 注意,因?yàn)樽詈笠粋€(gè)成員會(huì)被刪除,而如果這個(gè)成員里面有一個(gè)成員變量是指針, 那析構(gòu)函數(shù)很有可能會(huì)把這個(gè)指針指向的地方釋放掉! 這樣,即使最后一個(gè)成員被復(fù)制了一份 到倒數(shù)第2的位置,也因?yàn)樵谒旧肀粍h除的時(shí)候,把倒數(shù)第2個(gè)(也就是它的復(fù)制) 的指針成員所指向的地方給釋放了! 如圖:

解決的辦法也很簡(jiǎn)單, 最少有2種. 1, 增加作為vector類型的類的拷貝構(gòu)造函數(shù), 因?yàn)?span lang="EN-US">vector在erase的時(shí)候會(huì)發(fā)生一次拷貝,讓拷貝構(gòu)造函數(shù)不單單是復(fù)制指針,還把指針?biāo)赶虻膬?nèi)容給拷貝一份,這樣就不會(huì)導(dǎo)致被最后一個(gè)成員釋放的時(shí)候一起釋放掉了. 2, 如果有引用記數(shù)的話,如智能指針, 就不會(huì)被釋放掉了。不過(guò)如果一般編碼里面不需要用到引用記數(shù)的話,還是方法1比較簡(jiǎn)便