01.慎重選擇容器類型
選擇容器原則:需要考慮元素的排序情況,是否與標準相符,迭代器能力,元素佈局,與C的兼容性,查找速度,引用計數,插入刪除對事物語義的支持,某些操作是否會使迭代器無效,內存分配策略。
vector
需要使用隨機迭代器
容器中佈局需要與C兼容
deque
需要使用隨機迭代器
當大多數插入在頭部和尾部時
在尾部插入不會是迭代器,指針,引用變爲無效
string
需要使用隨機迭代器
介意使用引用計數計數,避免使用string,rope。string不可行
介意在容器上使用swap導致迭代器,指針,引用變成無效。string不可行
list
需要頻繁的在中間插入刪除
當大多數插入在頭部和尾部時
對多個元素的插入刪除需要事務語義
hash
查找速度是關鍵因素,選擇優先級爲hash->排序的vector->標準關聯容器
關注元素的排序不可行
序列容器(vector string deque list slist rope)
需要在容器的任何位置插入新元素
關聯容器
在容器中任意位置插入元素不可行
基於節點的容器(list,slist,關聯容器,hash)
在單個節點插入刪除時需要回滾能力
使迭代器,指針,引用變爲無效的次數最少
元素插入刪除時,避免移動容器中原來的元素
連續內存容器(vector,deque,string)
02.不要試圖編寫獨立於容器類型的代碼
原因:
- 不同容器的函數集不同
- 不同容器的同名函數返回值不同
- 不同容器使迭代器失效的規則不同
- 所編寫代碼只能使用這些容器的交集
03.確保容器中的對象拷貝正確而高效
注意點:
- 存放基類對象的容器,向其中插入派生類對象,會導致剝離。
- 使拷貝動作高效,正確,並防止剝離問題發生的一個簡單辦法使在容器中包含指針而不是對象。
04.調用empty而不是檢查size()是否爲0
原因:
- 使用empty性能優於判斷size()是否爲0
- empty是常數時間,有些list實現可能是線性時間
- list的size()和splice()只有一個可實現爲常數時間。
05.區間成員函數優先於與之對應的單元素成員函數
遺留問題:
vector::assign的實現方式
結論:
所有通過利用插入迭代器來限定目標區間的copy調用,都可以替換爲對區間成員函數的調用。
使用區間函數避免頻繁調用分配子,提升性能。
區間成員函數有:構造函數,區間插入,區間刪除,區間賦值。
06.當心C++編譯器最煩人的分析機制
以標準輸入裝置完成初始化操作
以下爲錯誤寫法:
std::deque<int> c(std::istream_iterator<int> (std::cin), std::istream_iterator<int>());
以上c被解析爲函數聲明。返回值爲std::deque<int>,第一個參數型別爲std::istream_iterator,參數名爲cin。第二個參數無名稱,型別是一個函數,不接受任何參數,返回值爲std::istream_iterator<int>。
正確寫法如下:
std::deque<int> c((std::istream_iterator<int> (std::cin)),(std::istream_iterator<int>()));
07.如果容器中包含了通過new操作符創建的指針,切記在容器對象析構前將指針delete掉
void doSomething() { vector<Widget*> vwp; // do something // for (vector<Widget*>::iterator i = vwp.begin(); i!= vwp.end(); ++i) delete *i }
以上代碼問題:在do something部分發生異常,則會造成資源泄露,vector中的動態申請的Widget不會被釋放。
解決方法:使用boost庫中的share_ptr智能指針。發生異常時,棧中對象的析構函數均會被調用。
刪除指針的仿函數模板
class DeleteObject { template<typename T> void operator()(const T* ptr) const { delete ptr; } }
08.切勿創建包含auto_ptr的容器對象
09.慎重選擇刪除元素的方法
刪除指定值
vector,string,deque:c.erase(remove(c.begin(), c.end(), value));
list:c.remove(value);
set,multiset,map,multimap:c.erase(value);基於等價(<)進行刪除
刪除判別式爲true的值
vector,string,deque:c.erase(remove_if(c.begin(), c.end(), judge));
for (SeqContainer<int>::iterator i = c.begin; i != c.end();) { if (judge(*i)) { // 處理*i i = c.erase(*i); } else ++i; }
list:c.remove_if(judge);
set,multiset,map,multimap:
remove_copy_if;c.swap
AssocContainer<int> c; for (AssocContainer<int>::iterator i = c.begin(); i != c.end();) { if (judge(*i)) c.erase(i++) else ++i }
11.切勿對STL容器的線程安全性有不切實際的依賴
對STL支持多線程的最多期望:
- 多個線程度時安全的
- 多個線程對不同容器做寫入操作時安全的