在開源項目或項目中使用git建立fork倉庫

前言:

vector我們經常使用,對vector裏面的基本函數構造函數、增加函數、刪除函數、遍歷函數我們也會用到。其中在使用遍歷之後erase刪除元素過程中,會出現一種刪除最後一個元素破壞了迭代器的情況。

如下所示 刪除到最後一個元素的時候就會報錯

vector<int> data(10);
auto temp_begin = data.begin(), temp_end= data.end();
for(;temp_begin!=temp_end;){
    data.erase(temp_begin);
}

產生這個問題的原因是:當我們調用erase方法刪除元素的時候,erase方法會返回下一個元素的迭代器。當刪除到最後一個元素的時候,這個時候返回的是最後一個元素之後的容器,而不是最後一個元素。

作者:良知猶存

轉載授權以及圍觀:歡迎關注微信公眾號:羽林君

或者添加作者個人微信:become_me


原因分析:

vector:

Because vectors keep an array format, erasing on positions other than the vector end also moves all the elements after the segment erased to their new positions, which may not be a method as efficient as erasing in other kinds of sequence containers (deque, list).
This invalidates all iterator and references to position (or first) and its subsequent elements.

假設你的 vector 中有多個對象,最後一個被標記為銷毀。當您調用erase時,它將返回一個新的有效迭代器,該迭代器指向已刪除元素之後的元素。被刪除的元素之後沒有元素,因此返回的迭代器為data.end()。

然後,我們繼續循環的頂部並取消引用此迭代器,這是無效的。如果要讓迭代器指向有效元素,則需要在擦除後減少其迭代器。
vec.end() 給你元素的迭代器以下容器的最後一個元素。看這裡:

list和vector區別(list 這樣刪除就沒事)

List:

This effectively reduces the list size by the number of elements removed, calling each element’s destructor before.

lists are sequence containers specifically designed to be efficient inserting and removing elements in any position, even in the middle of the sequence. Compared to the other base sequence containers (vector and deque), lists are the most efficient container erasing at some position other than the beginning or the end of the sequence, and, unlike in these, all of the previously obtained iterators and references remain valid after the erasing operation and refer to the same elements they were referring before (except, naturally, for those referring to erased elements).

列表是序列容器,專門設計用於在任何位置高效插入和刪除元素,甚至在序列的中間。list erase不會改變原來的iterator,所以不會出現像vector刪除最後一個iterator後程序錯誤。

修改建議

下面修改的建議都是讓vector的end迭代器可以一直更新,重新判斷當前位置。

vector<int> data(10);
auto iter = data.begin();
while(iter != data.end())
{
  data.erase(iter);
}
for (iter = data.begin(); it != data.end();)
{
    data.erase(iter);
}

將刪除最後一個元素

data.erase(data.end() - 1); 


 data.erase(data.begin() + data.size() - 1); 

應該提到的是,如果向量為空,則該操作將崩潰,因此出於安全考慮,我們可以再添加一個vector是否為空的判斷

if (!data.empty())
  data.erase(vec.end() - 1);

另外我們也發現 vector 的 erase 需要整個vector 移動,這個代價十分高,所以盡量少用。若排序順序不是很重要的話,可以和最後的那個item swap,然後刪掉最後那個,這樣可以顯著的提高效率。

結語

這就是我分享的項目中一些vector使用,如果大家有更好的想法和需求,也歡迎大家加我好友交流分享哈。


作者:良知猶存,白天努力工作,晚上原創公號號主。公眾號內容除了技術還有些人生感悟,一個認真輸出內容的職場老司機,也是一個技術之外豐富生活的人,攝影、音樂 and 籃球。關注我,與我一起同行。

                                                ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧  END  ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧

推薦閱讀

【1】C++的智能指針你了解嗎?

【2】嵌入式底層開發的軟件框架簡述

【3】CPU中的程序是怎麼運行起來的 必讀

【4】cartographer環境建立以及建圖測試

【5】設計模式之簡單工廠模式、工廠模式、抽象工廠模式的對比

本公眾號全部原創乾貨已整理成一個目錄,回復[ 資源 ]即可獲得。