閱讀607 返回首頁    go 阿裏雲 go 技術社區[雲棲]


C++容器使用經驗總結(一)

容器

1條:慎重選擇容器類型。

標準STL序列容器:vectorstringdequelist

標準STL關聯容器:setmultisetmapmultimap

非標準序列容器slistropeslist是一個單向鏈表,rope本質上是一“重型”string

非標準的關聯容器hash_sethase_multisethash_maphash_multimap

vector<char> 作為string的替代。(見第13)

vector作為標準關聯容器的替代。(見第23)

幾種標準的非STL容器,包括數組、bitsetvalarraystackqueuepriority_queue

你是否關心容器中的元素是如何排序的?如果不關心,選擇哈希容器.

容器中數據的布局是否需要和C兼容?如果需要兼容,就隻能選擇vector(見第16)

元素的查找速度是否是關鍵的考慮因素?如果是,就要考慮哈希容器、排序的vector和標準關聯容器-或許這就是優先順序。

對插入和刪除操作,你需要事務語義嗎?如果是,隻能選擇list。因為在標準容器中,隻有list對多個元素的插入操作提供了事務語義。

deque是唯一的、迭代器可能會變為無效(插入操作僅在容器末尾發生時,deque的迭代器可能會變為無效)而指向數據的指針和引用依然有效的標準STL容器。

2條:不要試圖編寫獨立於容器類型的代碼。

如果你想編寫對大多數的容器都適用的代碼,你隻能使用它們的功能的交集。不同的容器是不同的,它們有非常明顯的優缺點。它們並不是被設計用來交換使用的。

  你無法編寫獨立於容器的代碼,但是,它們(指客戶代碼)可能可以。

3條:確保容器中的對象拷貝正確而高效。

copy in,copy out,是STL的工作方式,它總的設計思想是為了避免不必要的拷貝。使拷貝動作高效並且防止剝離問題發生的一個簡單辦法是使容器包含指針而不是對象。

4條:調用empty而不是檢查size()是否為0

  理由很簡單:empty對所有的標準容器都是常數時間操作,而對一些list的實現,size耗費線性時間。

5條:區間成員函數優先於與之對應的單元素成員函數。

區間成員函數寫起來更容易,更能清楚地表達你的意圖,而且它們表現出了更高的效率。

6條:當心C++編譯器最煩人的分析機製。

把形參加括號是合法的,把整個形參的聲明(包括數據類型和形參名字)用括號括起來是非法的。

7條:如果容器中包含了通過new操作創建的指針,切記在容器對象析構前將指針delete掉。

STL很智能,但沒有智能到知道是否該刪除自己所包含的指針所指向的對象的程度。為了避免資源泄漏,你必須在容器被析構前手工刪除其中的每個指針,或使用引用計數形式的智能指針(比如Boostsharedprt)代替指針。

8條:切勿創建包含auto_ptr的容器對象。

拷貝一個auto_ptr意味著改變它的值。例如對一個包含auto_ptrvector調用sort排序,結果是vector的幾個元素被置為NULL而相應的元素被刪除了。

9條:慎重選擇刪除元素的方法。

要刪除容器中指定值的所有對象:

如果容器是vectorstringdeque,則使用erase-remove習慣用法。

SeqContainer<int> c;

c.erase(remove(c.begin(),c.end(),1963),c.end());

如果容器是list,則使用list::remove

如果容器是一個標準關聯容器,則使用它的erase成員函數。

要刪除容器中滿足特定條件的所有對象:

如果容器是vectorstringdeque,則使用erase-remove_if習慣用法。

如果容器是list,則使用list::remove_if

如果容器是一個標準關聯容器,則使用remove_copy_ifswap,或者寫一個循環遍曆容器的元素,記住當把迭代器傳給erase時,要對它進行後綴遞增。

AssocCOntainer<int> c;

...

AssocContainer<int> goodValues;

remove_copy_if(c.begin(), c.end(), inserter(goodValues, goodValues.end()),badValue);

c.swap(goodValues);

for(AssocContainer<int>::iterator i = c.begin();i !=c.end();/* do nothing */){

if(badValue(*i)) c.erase(i++);

else ++i;

}

要在循環內部做某些(除了刪除對象之外的)操作:

如果容器是一個標準序列容器,則寫一個循環來遍曆容器中的元素,記住每次掉用erase時,要用它的返回值更新迭代器。

如果容器是一個標準關聯容器,則寫一個循環來遍曆容器中的元素,記住每次把迭代器傳給erase時,要對迭代器做後綴遞增。

10條:了解分配子(allocator)的約定和限製。

11條:理解自定義分配子的合理用法。

12條:切勿對STL容器的線程安全性有不切實際的依賴。

對一個STL實現你最多隻能期望:

多個線程讀是安全的。

多個線程對不同的容器寫入操作是安全的。

你不能期望STL庫會把你從手工同步控製中解脫出來,而且你不能依賴於任何線程支持。


最後更新:2017-04-02 17:51:22

  上一篇:go Linux中新建表空間和用戶並授權
  下一篇:go cocos2dx-CCOrbitCamera類的問題解決