最近看了一本書《Effective STL》,這本書內容比較老,但里面很多內容還是值得我們學習的。書里一共有50條有效使用STL的經驗,這里整理出了30條自認為有用的條目分享給大家,希望對大家有所幫助,想了解具體內容的的朋友可以直接去看書哈。
以下是干貨:
1.慎重選擇STL容器類型
a)確保自己了解每個容器的使用場景,特定的場景選擇合適的容器類型
b)連續內存,支持下標訪問,可考慮選擇vector
c)頻繁的在中間做插入或者刪除操作,可考慮選擇list
d)兩者都有,可考慮使用deque
2.不要試圖編寫獨立于容器類型的代碼
a)不同容器有不同的成員函數,想獨立于容器類型,只能取它們的交集
b)然而,取交集意義不大
3.確保容器中的對象拷貝正確而高效
a)大家應該都知道,容器中存放的都是對象的拷貝,想要拷貝正確那就實現拷貝構造函數和拷貝賦值運算符
b)想要更高效,可以使容器包含指針而不是對象,也可考慮智能指針
4.調用empty而不是檢查size()是否為0
a)empty對所有的標準容器都是常數時間操作,而對一些list實現,size耗費線性時間
5.區間成員函數優先于與之對應的單元素成員函數
a)寫起來更方便,代碼更少
b)更能清晰的表達意圖
c)有些情況下可能更高效
6.如果容器中包含了通過new操作創建的指針,切記在容器對象析構前將指針delete掉
a)其實就是為了避免資源泄漏
b)可以考慮在容器中存儲shared_ptr
7.慎重選擇刪除元素的方法
a)要刪除容器中有特定值的所有對象
i.如果容器是vector、string或deque,則使用erase-remove習慣用法
ii.如果容器是list,則使用list::remove
iii.如果容器是一個標準關聯容器,則使用它的erase成員函數
b)要刪除容器中滿足特定條件的所有對象
i.如果容器是vector、string或deque,則使用erase-remove_if習慣用法
ii.如果容器是list,則使用list::remove_if
iii.如果容器是一個標準關聯容器,則使用remove_copy_if和swap,或者寫一個循環來遍歷容器中的元素,記住當把迭代器傳給erase時,要對它進行后綴遞增
c)要在循環內部做某些操作
i.如果容器是一個標準序列容器,則寫一個循環來遍歷容器中的元素,記住每次調用erase時,要用它的返回值更新迭代器
ii.如果容器是一個標準關聯容器,則寫一個循環來遍歷容器中的元素,記住當把迭代器傳給erase時,要對迭代器做后綴遞增。
d)返回值更新迭代器示例
for(autoi=c.begin();i!=c.end();){
if(xxx){
i=c.erase(i);
}
else++i;
}
e)迭代器后綴遞增示例
for(autoi=c.begin();i!=c.end();){
if(xxx){
c.erase(i++);
}
else++i;
}
f)(!!!)現在可以統一使用返回值更新迭代器方式
8.切勿對STL容器的線程安全性有不切實際的依賴
a)書中原話是:當涉及STL容器和線程安全性時,你可以指望一個STL庫允許多個線程同時讀一個容器,以及多個線程對不同的容器做寫入操作。你不能指望STL庫會把你從手工同步控制中解脫出來,而且你不能依賴于任何線程支持。
b)原文磨磨唧唧的,我就可以理解為STL不支持線程安全,想要線程安全,那自己加鎖就完事兒了。
9.vector等容器考慮使用reserve來避免不必要的重新分配
a)這種動態擴容的容器每次擴容都會大體經歷4步:
i.分配一塊大小為當前容量的某個倍數的新內存。大多數實現中,vector和string的容器每次以2的倍數增長
ii.把容器的所有元素從舊的內存移動或者拷貝到新的內存中
iii.如果有拷貝,析構掉舊內存中的對象
iv.如果有拷貝,釋放舊內存
b)明確size()、capacity()、resize()、reserve()四個成員函數的具體含義
c)reserve能使重新分配的次數減少到最低限度,避免重新分配和迭代器失效帶來的開銷,兩種方式:
i.若能明確知道或預計容器最終有多少元素,可使用reverse,預留適當大小的空間
ii.先預留足夠大的空間,然后,當把所有數據都加入以后,再去除多余的空間。
10.使用swap技巧除去多余的容量
a)vector().swap(a)
b)a.clear()
c)以上兩種都是清空容器的方法,swap相對于clear一般更合適一些
11.避免使用vector存儲bool
a)有兩點:
i.它不是一個STL容器,不能取元素的地址
ii.它不存儲bool
b)可以用deque和bitset來替代
12.理解相等和等價的區別
a)相等的概念基于operator==,即a==b,則為相等
b)如果!(a < b) && !(b < a),則為等價
13.為包含指針的關聯容器指定比較類型
a)容器里面存儲的都是指針,但是由于是關聯容器,需要進行比較,但默認的比較(比較指針)一般不是我們想要的行為
b)所以需要指定比較類型,自定義比較行為
14.總是讓比較函數在等值情況下返回false
a)直接看這個文章吧【線上問題】P1級公司故障,年終獎不保,很不錯
15.切勿直接修改set或multiset中的鍵
a)如果改變了鍵,那么可能破壞該容器(順序),再使用該容器可能導致不確定的結果
b)為什么標題是切勿修改set,而不是切勿修改map中的鍵呢?
i.因為map中的鍵是const K,本來就不允許修改
16.考慮用排序的vector替代關聯容器
a)在排序的vector中存儲數據可能比在標準關聯容器中存儲同樣的數據要耗費更少的內存。
b)由于Page Fault,通過二分搜索來查找一個排序的vector可能比查找一個標準關聯容器要更快一些
c)對于排序的vector,最不利的地方在于它必須保持有序,這對vector來說,代價是很高的。所以,在查找操作幾乎從不跟插入刪除操作混在一起時,使用排序的vector才更合適。
17.當效率至關重要時,請在map::operator[]與map::insert之間謹慎做出選擇
a)當向map中添加元素時,優先選用insert而不是operator[]
b)當更新map中的值時,優先選用operator[]
18.iterator優先于const_iterator、reverse_iterator、const_reverse_iterator
a)盡量用iterator來代替const或reverse型的迭代器
b)iterator相對于其它更加實用
c)很多參數都是iterator,很少有其它
19.使用distance和advance將容器的const_iterator轉換成iterator
Containerd;
ConstIterci;
Iteri(d.begin());
advance(i,distance(i,ci));
20.對于逐個字符的輸入, 請考慮使用istreambuf_iterator
a)istreambuf_iterator性能一般優于istream_iterator
b)istreambuf_iterator不會跳過任何字符
istreaminputFile("xxx.txt");
stringstr(istreambuf_iterator(inputFile),istreambuf_iterator());
21.容器的插入, 要確保目標空間足夠大
a)靈活使用reverse和back_inserter、front_inserter和inserter返回的迭代器。
22.了解各種與排序有關的選擇
a)重點關注以下幾項:
i.partial_sort
ii.nth_element
iii.stable_sort
iv.sort
v.partition
vi.stable_partition
b)對排序算法的選擇應該更多地基于所需要完成的功能,而不是算法的性能
c)總結:
i.如果需要對vector、string、deque或者數組中的元素執行一次完全排序,那可以使用sort或者stable_sort
ii.如果有一個vector、string、deque或者數組,并且只需要對等價性最前面的n個元素進行排序,那可以使用partial_sort
iii.如果有一個vector、string、deque或者數組,并且需要找到第n個位置上的元素,或者,需要找到等價性最前面的n個元素但又不必對這n個元素進行排序,那么,nth_element正是所需要的函數
iv.如果需要將一個標準序列容器中的元素按照是否滿足某個特定的條件區分開來,那么,partition和stable_partition可能正是你所需要的
v.如果你的數組在一個list中,那么你仍然可以調用partition和stable_partition算法,可以用list::sort來替代sort和stable_sort算法。
23.如果確實需要刪除元素,則需要在remove這一類算法之后調用erase
a)erase-remove這塊應該大家都知道
b)list是個例外,list的remove就是erase
c)remove指針時注意釋放掉對應的內存,防止內存泄漏
24.了解哪些算法使用排序的區間作為參數
a)某些算法為了性能考慮,需要使用排序的區間作為參數
b)如果傳遞了沒有排序的區間進去,會導致錯誤的結果
c)要求排序區間的STL算法:
i.binary_search
ii.lower_bound
iii.upper_bound
iv.equal_range
v.set_union
vi.set_intersection
vii.set_difference
viii.set_symmetric_difference
ix.merge
x.inplace_merge
xi.includes
d)下面的算法不一定要求排序區間,但通常和排序區間一起使用
i.unique
ii.unique_copy
25.通過mismatch或lexicographical_compare實現簡單的忽略大小寫的字符串比較
a)mismatch或lexicographical_compare更通用
b)但strcmp在處理長字符串時可能更高效
26.使用accumulate或者for_each進行區間統計
a)accumulate會計算出一個區間的統計信息
b)for_each是對一個區間的每個元素做一個操作
27.算法調用優先于手寫的循環
a)大多數情況下,標準的STL肯定比我們自己手寫的好一些,包括正確性以及性能和可維護性方面
b)比如:
i.min_element
ii.accumulate
iii.partition
iv.find
v.find_if
vi.for_each
vii.erase-remove
viii.transform
28.容器的成員函數優先于同名的算法
a)關聯容器提供了count、find、lower_bound、upper_bound、equal_range
b)list提供了remove、remove_if、unique、sort、merge、reverse
c)有兩個原因:
i.成員函數通常與容器(特別是關聯容器)結合得更加緊密
ii.成員函數往往速度更快
29.正確區分count、find、binary_search、lower_bound、upper_bound、equal_range
30.考慮使用函數對象而不是函數作為STL算法的參數
a)現在一般都是使用lambda表達式作為STL算法參數
審核編輯 :李倩
-
容器
+關注
關注
0文章
499瀏覽量
22091 -
STL
+關注
關注
0文章
86瀏覽量
18349 -
迭代器
+關注
關注
0文章
44瀏覽量
4330
原文標題:Effective STL, 30 條有效使用 STL 的經驗
文章出處:【微信號:LinuxHub,微信公眾號:Linux愛好者】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論