關於 C++ vector 的兩個小 tips

原本這篇文章標題我想起成《關於 vector 的兩個小坑》,後來想一想,其實也不算是坑,仍是本身對原理性的東西理解的沒作那麼透徹。工做中遇到的不少問題,後來歸根到底都是基礎不牢靠。安全

vector 擴容

這個問題很經典了,但仍是不當心踩到。有一個需求是要對目標元素進行復制,而目標元素集合是保存在 vector 裏面,因而簡單思考下就有以下代碼(大體含義):函數

void Duplidate(vector<Element>* element_list, Element* element) {
  element_list.push_back(*element);
}

void Process() {
  for (auto& package : package_list) {
    if (IsNeedDuplicate()) {
      Duplicate(element_list, package->element);
    }
  }
}

看起來好像沒什麼問題,就是當前的 package 對象是否知足複製的要求,須要的話,就對 package 的成員 origin_element 進行復制。跑 UT 也正常,而後在測試的時候就 coredump 了。看 core 文件就是掛在了複製的時候。這裏我一開始就沒明白,一個簡單的複製爲何會有 coredump。學習

檢查了好久 element 複製的場景,甚至想要專門寫一個拷貝構造函數。最後才恍然大悟,origin_element 指針指向的就是 element_list 裏面的元素,element_list 是總體流程的數據源,packge 對象是封裝的中間處理對象。以前的開發人員爲了方便,直接在 package 對象上保存了原始的 element 指針,而這個指針指向的是一個 vector 裏的元素。而我新加的邏輯會往原始的 vector 裏面再添加元素,那麼就有可能致使 vector 擴容,而 vector 擴容會致使總體的複製,從而致使原來指向這些元素的指針都失效了,靠後的 package 對象再去訪問 origin_element 就產生了 coredump。測試

固然,從設計上來講,就不該該保存指向 vector 元素的指針,可是這裏有太多舊代碼牽涉,這裏就不作討論。設計

vector::erase()

原由是我在代碼裏面新增了以下代碼(大體):指針

void EraseElement(const vector<Element>::iterator& element_iter,
                vector<Element>& element_list) {
  while (element_iter != element_list.end()) {
    element_list.erase(element_iter);
  }
}

而後 cr 的同窗提出了一個疑問是 element_iterconst 不可變的,可是在函數裏有擦除了對應的元素,這裏會不會有問題?雖然 UT 都已經跑過了,可是這種寫法的確比較奇怪,因而就藉機學習了一下 vector::erase() 的實現原理跟用法。code

erase(iterator) 的實現原理其實不會改變 iterator,而是把後面的元素一個個往前移動,至關因而 iterator 指向的元素自己發生了變化,因此能夠用 const 來修飾這個 iterator。可是這裏用 cosnt & 實際上是沒有錯可是無用的修飾,除了容易讓人誤判以外,其實沒有什麼實際用途。我以前是爲了修正 cpplint 才把reference 改爲 const reference。對象

另外 erase 自己的確比較危險,主要仍是 erase 的時候 iterator 自己沒發生變化,可是指向的元素變了,,在不少時候 iterator 會天然地指向下一個元素,可是因爲這是未定義的行爲,這裏面可能會有不可預期的地方,因此最終改爲顯示的獲取返回從新賦值(erase() 會返回下一個迭代器,但這一點經常被忽略),這樣就能保證安全性了。更安全更推薦的作法應該是使用 remove_if() 這裏就不展開講了。element

void EraseElement(vector<Element>& element_list,
                vector<Element>::iterator element_iter ) {
  while (element_iter != element_list.end()) {
    element_iter = element_list.erase(element_iter);
  }
}
相關文章
相關標籤/搜索