Effective stl---笔记
1 只有序列容器支持push_front或push_back,
? 只有關聯容器支持count和lower_bound,等等.
2 (條款1解釋了deque是唯一一個在迭代器失效的
??? 情況下指針和引用仍然有效的東西)? 【不作為特例】
3 迭代器/指針/參考的失效規則
4 typedef代碼封裝
?? ?typedef vector<Widget> WidgetContainer;
?? ?typedef WidgetContainer::iterator WCIterator;
?? ?WidgetContainer cw;
? 更高等級的封裝,限制權限,使用class CustomList含有List
5 nth_element算法? 【讓第n+1大/小的數據,出現在v[n],且它是數據的大小分水嶺,兩邊數據不保證有序】
6? 拷進去,拷出來。這就是STL的方式。是的,拷貝對象是STL的方式。
7 基類對象容器,當然由于繼承的存在,拷貝會導致分割。【splice】
8 我們也可以建立一個可以足夠包含maxNumWidgets個Widget的空vector,但沒有構造Widget:
? vector<Widget> vw;
? vw.reserve(maxNumWidgets); // reserve的詳細信息請參見條款14
? 【比數組文明多了(數組直接用默認構造函數構造對象了)】
?
9 盡量調用empty(splice導致不能常數時間知道size是否為0,必須要去計數)【區間插入?】
10 第一,它提供給我一個機會來提醒你assign成員函數的存在,
?? 太多的程序員沒注意到這是一個很方便的方法。
?? 它對于所有標準序列容器(vector,string,deque和list)都有效。
?? 【替代數據集】
? ?
?11 v1.clear();
??? copy(v2.begin() + v2.size() / 2, v2.end(), back_inserter(v1));
??? 寫這些仍然比寫assign的調用要做更多的工作。
??? 此外,雖然在這段代碼中沒有表現出循環,在copy中的確存在一個循環(參見條款43)。
??? 結果,效率損失仍然存在。在這里,我要離題一下來指出幾乎所有目標區間是通過
??? 插入迭代器(比如,通過inserter,back_inserter或front_inserter)指定的copy的使用
??? 都可以——應該——通過調用區間成員函數來代替。
??? 比如這里,這個copy的調用可以用一個insert的區間版本代替:
??? v1.insert(v1.end(), v2.begin() + v2.size() / 2, v2.end());
12 一般來說使用區間成員函數可以輸入更少的代碼。
?? 區間成員函數會導致代碼更清晰更直接了當。
13? ● 區間構造。所有標準容器都提供這種形式的構造函數:
?? container::container(InputIterator begin, // 區間的起點
??????????????????????? InputIterator end); // 區間的終點
??? 如果傳給這個構造函數的迭代器是istream_iterators或istreambuf_iterators(參見條款29),
??? 你可能會遇到C++的最驚異的解析,原因之一是你的編譯器可能會因為把這個構造看作一個函數
??? 聲明而不是一個新容器對象的定義而中斷。條款6告訴你需要知道所有關于解析的東西,包括怎么對付它。
?? ● 區間插入。所有標準序列容器都提供這種形式的insert:
??? void container::insert(iterator position, // 區間插入的位置
?????????????????????????? InputIterator begin, // 插入區間的起點
?????????????????????????? InputIterator end); // 插入區間的終點
??? 關聯容器使用它們的比較函數來決定元素要放在哪里,所以它們了省略position參數。
??? void container::insert(lnputIterator begin, InputIterator end);
??? 當尋找用區間版本代替單元素插入的方法時,不要忘記有些單元素變量用采用不同的函數名偽裝它們自己。
??? 比如,push_front和push_back都把單元素插入容器,即使它們不叫insert。如果你看見一個循環調用push_front或
??? push_back,或如果你看見一個算法——比如copy——的參數是front_inserter或者back_inserter,你就發現了一個
??? insert的區間形式應該作為優先策略的地方。
?? ● 區間刪除。每個標準容器都提供了一個區間形式的erase,但是序列和關聯容器的返回類型不同。
???? 序列容器提供了這個:
???? iterator container::erase(iterator begin, iterator end);
???? 而關聯容器提供這個:
???? void container::erase(iterator begin, iterator end);
為什么不同?解釋是如果erase的關聯容器版本返回一個迭代器(被刪除的那個元素的下一個)會招致一個無法
????? 接受的性能下降。我是眾多發現這個徒有其表的解釋的人之一,但標準說的就是標準說的,標準說erase的序列
和關聯容器版本有不同的返回類型。
這個條款的對insert的性能分析大部分也同樣可以用于erase。單元素刪除的函數調用次數仍然大于一次調用區間
刪除。當使用單元素刪除時,每一次元素值仍然必須向它們的目的地移動一位,而區間刪除可以在一個單獨的
移動中把它們移動到目標位置。
關于vector和string的插入和刪除的一個論點是必須做很多重復的分配。(當然對于刪除,會發生重復的回收。)
那是因為用于vector和string的內存自動增長來適應于新元素,但當元素的數目減少時它不自動收縮。(條款17描
述了你怎么減少被vector或string持有的不必要的內存。)
一個非常重要的區間erase的表現是erase-remove慣用法。你可以在條款32了解到所有關于它的信息。
?? ● 區間賦值。就像我在這個條款的一開始提到的,所有標準序列容器都提供了區間形式的assign:
void container::assign(InputIterator begin, InputIterator end);
所以現在我們明白了,盡量使用區間成員函數來代替單元素兄弟的三個可靠的論點。
????? 區間成員函數更容易寫,它們更清楚地表達你的意圖,而且它們提供了更高的性能。那是很難打敗的三駕馬車。
14 ifstream dataFile("ints.dat");
???? istream_iterator<int> dataBegin(dataFile);
???? istream_iterator<int> dataEnd;
???? list<int> data(dataBegin, dataEnd);
??? 命名迭代器對象的使用和普通的STL編程風格相反,但是你得判斷這種方法對編譯器和必須使用編譯器的人
??? 都模棱兩可的代碼是一個值得付出的代價。
??? 【注意stream類似的迭代器,都給予命名】
15 它們能告訴你所容納的對象類型(通過value_type的typedef)
16 銷毀new 使用foreach? 和 模板函數對象
?? struct xx
?? {
???? template<typename T>
???? void operator()(const T *p) const
???? {
??????? delete p;
??????? //p = NULL; //置null沒意義,且是const,小心多次delete
???? }
?? }
? ?
?? 如果在foreach之前拋異常,可以使用智能指針boost shared_ptr來避免泄漏。
? ?
17? 如果你有一個連續內存容器(vector、deque或string——參見條款1),
???? 最好的方法是erase-remove慣用法(參見條款32):
c.erase(remove(c.begin(), c.end(), 1963), // 當c是vector、string
??????? ??????????????????????????????????????????????? c.end()); // 或deque時,
// erase-remove慣用法
// 是去除特定值的元素
// 的最佳方法
這方法也適合于list,但是,正如條款44解釋的,list的成員函數remove更高效:
c.remove(1963); // 當c是list時,
// remove成員函數是去除
// 特定值的元素的最佳方法
對于關聯容器,解決問題的適當方法是調用erase:
? c.erase(1963); // 當c是標準關聯容器時
// erase成員函數是去除
// 特定值的元素的最佳方法
18? 因為它為vector、string和deque產生未定義的行為!要記得對于那樣的容器,
調用erase不僅使所有指向被刪元素的迭代器失效,也使被刪元素之后的所有迭代器失效。
19 如果我們觀察在本條款中提到的所有東西,我們得出下列結論:
● 去除一個容器中有特定值的所有對象:
如果容器是vector、string或deque,使用erase-remove慣用法。
如果容器是list,使用list::remove。
如果容器是標準關聯容器,使用它的erase成員函數。
● 去除一個容器中滿足一個特定判定式的所有對象:
如果容器是vector、string或deque,使用erase-remove_if慣用法。
如果容器是list,使用list::remove_if。
如果容器是標準關聯容器,使用remove_copy_if和swap,或寫一個循環來遍歷容器元素,當你把迭代器傳給erase時記得后置遞增它。
● 在循環內做某些事情(除了刪除對象之外):
如果容器是標準序列容器,寫一個循環來遍歷容器元素,每當調用erase時記得都用它的返回值更新你的迭代器。
如果容器是標準關聯容器,寫一個循環來遍歷容器元素,當你把迭代器傳給erase時記得后置遞增它。
20? 當涉及到線程安
全和STL容器時,你可以確定庫實現允許在一個容器上的多讀取者和不同容器上的多寫入者
【使用鎖 RAII機制在構造函數里上鎖(傳容器為參數)】
21 3. 你必須確保只delete一次。如果一個分配被刪除了不止一次,結果也會未定義。
?? 【多次delete空不會產生問題】
? ?
22 string使用引用計數的話,多線程下不安全。可以用vector<char> 替代。
? 【對于多線程,我們應該設計盡量避免競態條件,此是根本,謹慎設計共享變量】
23 使用reserve來避免不必要的重新分配
24 事實上,讓C風格API把數據放入一個vector,然后拷到你實際想要的STL容器中的主意總是有效的。
?? 【同理,可以將stl容器通過vector再轉回C Api中,vector是橋】
? ?
?? if( !v.empty() )
?? {
???? dosomething(&v[0],v.size()); //不要用v.begin()
?? }
25 vector<Contestant>(contestants).swap(contestants); ???
?? 所以當你想對vector和string進行“收縮到合適”時,就考慮“交換技巧”。
?? string().swap(s); // 清除s而且最小化它的容量
? ?
26 標準庫提供了兩個替代品,它們能滿足幾乎所有需要。第一個是deque<bool>。deque提供了幾乎所有vector所
提供的(唯一值得注意的是reserve和capacity),而deque<bool>是一個STL容器,它保存真正的bool值。當
然,deque內部內存不是連續的。所以不能傳遞deque<bool>中的數據給一個希望得到bool數組的C API[1](參
見條款16),但你也不能讓vector<bool>做這一點,因為沒有可移植的取得vector<bool>中數據的方法。
? ?
?? 【vector<bool>不滿足STL容器的必要條件,你最好不要使用它。】
?? 【vector<bool>的位域實現。】
? ?
?? 如果不在乎沒有迭代器和動態改變大小,你也許會發現bitset正合你意。
? ?
27 《綠野仙蹤》。全世界最有名的童話
片之一,榮獲1939年奧斯卡最佳電影歌曲和最佳電影配樂。其中的多色馬,關聯容器是不同顏色的生物。真
的,它們共享了序列容器的很多特性,但它們在很多基本方法上不同
28 find
對“相同”的定義是相等,基于operator==。set::insert對“相同”的定義是等價,通常基于operator<。
等價一般在每種標準關聯容器(比如,set、multiset、map
和multimap)的一部分——排序順序方面有意義
29 。set<Widget>的默認比較函數是less<Widget>,而默認的less<Widget>簡單地對Widget調用
operator<,所以w1和w2關于operator<有等價的值如果下面表達式為真:
!(w1 < w2) // w1 < w2時它非真
&& // 而且
!(w2<w1) // w2 < w1時它非真
在一般情況下,用于關聯容器的比較函數不是operator<或甚至less,它是用戶定義的判斷式。(關于判斷式的
更多信息參見條款39。)每個標準關聯容器通過它的key_comp成員函數來訪問排序判斷式,所以如果下式求
值為真,兩個對象x和y關于一個關聯容器c的排序標準有等價的值:
!c.key_comp()(x, y) && !c.key_comp()(y, x) // 在c的排序順序中
// 如果x在y之前它非真,
// 同時在c的排序順序中
// 如果y在x之前它非真
30? if (ciss.find("persephone") != ciss.end())... // 這個測試會成功
但如果我們用非成員的find算法,搜索會失敗:
if (find(ciss.begin(), ciss.end(),
"persephone") != ciss.end())... // 這個測試會失敗
那是因為“persephone”等價于“Persephone”(關于比較仿函數CIStringCompare),但不等于它(因為string
("persephone") != string("Persephone"))。這個例子演示了為什么你應該跟隨條款44的建議優先選擇成員函數
(就像set::find)而不是非成員兄弟(就像find)的一個理由。
容器的比較函數對象。算法find用的==
31 通過只使用一個比較函數并使用等價作為兩個值“相等”的意義的仲裁者
32 你應該回憶起
set<string*> ssp;
是這個的簡寫:
set<string*, less<string*> > ssp;
好,為了完全準確,它是
set<string*, less<string*>, allocator<string*> > ssp;
33 令人遺憾的是,stringPtrLess不是一種類型,它是一個
函數。這就是為什么嘗試使用stringPtrLess作為set的比較函數不能編譯的原因,set不要一個函數,它要的是能在內部用實例化建立函數的一種類型。
?【for_each可以使用函數】
?
?struct DereferenceLess {
????? template <typename PtrType>
????? bool operator()(PtrType pT1, // 參數是值傳遞的,
????????????????????? PtrType pT2) const // 因為我們希望它們
????? { // 是(或行為像)指針
???????????????? return *pT1 < *pT2;
????? }
};
34 比較函數總應該對相等的值返回false。
35 強制類型轉換,產生一個臨時對象
? if (i != se.end()) { ????????????????????????????// 同上,
??????? ((Employee)(*i)).setTitle("Corporate Deity"); // 但使用C
} ???????????????????????????????????????????????// 強轉語法
【類似于】
if (i != se.end()){
???????? Employee tempCopy(*i); // 把*i拷貝到tempCopy
???????? tempCopy.setTitle("Corporate Deity"); // 修改tempCopy
}?? ?
36 如果你要總是可以工作而且總是安全地改變set、multiset、
??? map或multimap里的元素,按五個簡單的步驟去做:
1. 定位你想要改變的容器元素。如果你不確定最好的方法,條款45提供了關于怎樣進行適當搜尋的指導。
2. 拷貝一份要被修改的元素。對map或multimap而言,確定不要把副本的第一個元素聲明為const。畢竟,你想要改變它!
3. 修改副本,使它有你想要在容器里的值。
4. 從容器里刪除元素,通常通過調用erase(參見條款9)。
5. 把新值插入容器。如果新元素在容器的排序順序中的位置正好相同或相鄰于刪除的元素,使用insert的“提示”形式把插入的效率從對數時間改進到分攤的常數時間。使用你從第一步獲得的迭代器作為提示。
37? EmpIDSet se; // 同前,se是一個以ID號
// 排序的雇員set
Employee selectedID; // 同前,selectedID是一個帶有
// 需要ID號的雇員
...
EmpIDSet::iterator i =
se.find(selectedID); ?????????// 第一步:找到要改變的元素
if (i!=se.end()){
Employee e(*i); ??????????????// 第二步:拷貝這個元素
se.erase(i++); ??????????????// 第三步:刪除這個元素;
???????????????????????????? // 自增這個迭代器以
????????????????????????????? // 保持它有效(參見條款9)
e.setTitle("Corporate Deity"); // 第四步:修改這個副本
se.insert(i, e); ?????????????// 第五步:插入新值;提示它的位置
????????????????????????????? // 和原先元素的一樣
}
你將原諒我以這種方法放它,但要記得關鍵的事情是對于set和multiset,如果你進行任何容器元素的原地修改,你有責任確保容器保持有序
【原地修改不要修改set的key】
38 一旦你寫了DataCompare,東西都很好的依序排列了。而一旦位置合適了,只要你的程序按照
101頁描述的階段方式使用數據結構,它們往往比相應的使用真的map的設計運行得更快而且使用更少內存。
如果你的程序不是按照階段的方式操作數據結構,那么使用有序vector代替標準關聯容器幾乎可以確定是在
浪費時間。
39 如果你要更新已存在的map元素,operator[]更好,但如果你要增
加一個新元素,insert則有優勢。
【人如其名】
40 盡量用iterator代替const_iterator,reverse_iterator和
const_reverse_iterator
41 因為它可能花費線性時間的代價來產生一個和const_iterator等價的iterator,并且因為如果不能訪問
const_iterator所屬的容器這個操作就無法完成。從這個角度出發,也許你需要重新審視你從const_iterator產生
iterator的設計。事實上那樣的考慮幫助激發了條款26,它建議你當處理容器時盡量用iterator代替const和reverse迭代器。
42 reverse_iterator的base成員函數返回一個“對應的”iterator的說法并不準確。對于插入操
作而言,的確如此;但是對于刪除操作,并非如此。當需要把reverse_iterator轉換成iterator的時候,有一點非
常重要的是你必須知道你準備怎么處理返回的iterator,因為只有這樣你才能決定你得到的iterator是否是你需
要的。
【并不是真正對著同一個位置】
43 當你了解它之后,你也應該考慮把ostreambuf_iterator用于相應的無格式一個一個字符輸出的作。它們沒有了
ostream_iterator的開銷(和靈活性),所以它們通常也做得更好。
44
無論何時你使用一個要求指定目的區間的算法,確保目的區間已經足夠大或者在算法執行時可以增加大小。
如果你選擇增加大小,就使用插入迭代器,
比如ostream_iterators或從back_inserter、front_inserter或inserter返回的迭代器。
這是所有你需要記住的東西。
45
● 如果你需要在vector、string、deque或數組上進行完全排序,你可以使用sort或stable_sort。
● 如果你有一個vector、string、deque或數組,你只需要排序前n個元素,應該用partial_sort。
● 如果你有一個vector、string、deque或數組,你需要鑒別出第n個元素或你需要鑒別出最前的n個元素,
???????????? 而不用知道它們的順序,nth_element是你應該注意和調用的。
● 如果你需要把標準序列容器的元素或數組分隔為滿足和不滿足某個標準,你大概就要找partition或stable_partition。
● 如果你的數據是在list中,你可以直接使用partition和stable_partition,你可以使用list的sort來代替sort和stable_sort。
如果你需要partial_sort或nth_element提供的效果,你就必須間接完成這個任務,但正如我在上面勾畫的,會有很多選擇。
46 需要更少資源(時間和空間)的算法列在需要更多的前面:
1. Partition
2. stable_partition
3. nth_element
4. partial_sort
5. sort
6. stable_sort
47 一旦你知道了remove不能“真的”從一個容器中刪除東西,和erase聯合使用就變成理所當然了。你要記住的
唯一其他的東西是remove不是唯一這種情況的算法。另外有兩種“類似remove”的算法:remove_if和unique。
remove和remove_if之間的相似性很直截了當。所以我不會細講,但unique行為也像remove。它用來從一個區
間刪除東西(鄰近的重復值)而不用訪問持有區間元素的容器。結果,如果你真的要從容器中刪除元素,你
也必須成對調用unique和erase,unique在list中也類似于remove。
正像list::remove真的刪除東西(而且比eraseremove慣用法高效得多)。
list::unique也真的刪除鄰近的重復值(也比erase-unique高效)。
【成員函數好,成員函數好】
48 不管你怎么選擇處理動態分配指針的容器,通過引用計數智能指針、在調用類似remove的算法前手動刪除和
廢棄指針或者一些你自己發明的技術,本條款的指導意義依然一樣:提防在指針的容器上使用類似remove的算法。
沒有注意這個建議的人只能造成資源泄漏
【remove的機制造成】
49 我知道你們中的一部分會用蠻力記憶,所以這里有一個只能操作有序數據的算法的表:
binary_search lower_bound
upper_bound equal_range
set_union set_intersection
set_difference set_symmetric_difference
merge inplace_merge
includes
50 11個名字帶“copy”的算法:
copy copy_backward
replace_copy reverse_copy
replace_copy_if unique_copy
remove_copy rotate_copy
remove_copy_if partial_sort_copy
unintialized_copy
51 用accumulate或for_each來統計區間
52 BPFC::operator()的實現例證了BPFC所有的虛函數是怎么實現的:它們調用了在BPFCImpl中它們真的虛函
數。結果是仿函數類(BPFC)是小而單態的,但可以訪問大量狀態而且行為多態。
我在這里忽略了很多細節,因為我勾勒出的基本技術在C++圈子中已經廣為人知了。《Effective C++》的條款34中有。
在Gamma等的《設計模式》[6]中,這叫做“Bridge模式”。Sutter在他的《Exceptional C++》[8]中叫它“Pimpl慣用法”.
從STL的視角看來,要記住的最重要的東西是使用這種技術的仿函數類必須支持合理方式的拷貝。如果你是
上面BPFC的作者,你就必須保證它的拷貝構造函數對指向的BPFCImpl對象做了合理的事情。也許最簡單的合理的東西是引用計數,使用 類似Boost的shared_ptr,你可以在條款50中了解它.
實際上,對于本條款的目的,唯一你必須擔心的是BPFC的拷貝構造函數的行為,因為當在STL中被傳遞或從
一個函數返回時,函數對象總是被拷貝——值傳遞,記得嗎?那意味著兩件事。讓它們小,而且讓它們單態。
53 (not1、not2、bind1st和bind2nd)都需要存在某些typedef
54? 這是STL里的一個普遍習慣:函數和函數對象總使用用于非成員函數
的語法形式調用
55? 了解使用ptr_fun、mem_fun和mem_fun_ref的原因
56 不要通過把less的定義當兒戲來誤導那些程序員。如果你使用less(明確或者隱含),保證它表示operator<。
如果你想要使用一些其他標準排序對象,建立一個特殊的不叫做less的仿函數類
57
● 效率:算法通常比程序員產生的循環更高效。
● 正確性:寫循環時比調用算法更容易產生錯誤。
● 可維護性:算法通常使代碼比相應的顯式循環更干凈、更直觀。
58 ?
??? 幾乎不可能被打敗的sort及其同族算法(比如,
??? stable_sort(),nth_element()等,參見條款31);適用于有序區間的搜索算法(比如,binary_search,
??? lower_bound等,參見條款34和35)也一樣好;就算是很平凡的任務,比如從連續內存容器中除去一些對象,
??? 使用erase-remove慣用法都比絕大多數程序員寫的循環更高效
?? 【盡量使用stl提供的算法,人那是計算機科學家寫的】
59? 在算法調用與手寫循環正在進行的較量中,關于代碼清晰度的底線是:這完全取決于你想在循環里做的是什
??? 么。如果你要做的是算法已經提供了的,或者非常接近于它提供的,調用泛型算法更清晰。如果循環里要做
?? 的事非常簡單,但調用算法時卻需要使用綁定和適配器或者需要獨立的仿函數類,你恐怕還是寫循環比較
??? 好。最后,如果你在循環里做的事相當長或相當復雜,天平再次傾向于算法。因為長的、復雜的通常總應該
?? 封裝入獨立的函數。只要將循環體一封裝入獨立函數,你幾乎總能找到方法將這個函數傳給一個算法(通常
?? 是for_each),以使得最終代碼直截了當。
?? 只要能用高層次的術語——如insert、find和for_each,
?? 取代了低層次的詞匯——如for、while和do,我們就提升了軟件的【【抽象】】層次
60? 當面臨著STL算法和同名的容器成員函數間進行選擇時,你應該盡量使用成員函數。幾
????? 乎可以肯定它更高效,而且它看起來也和容器的慣常行為集成得更好。
【私人定制服務】
61 count和find是線性時間的,但有序區間的
??? 搜索算法(binary_search、lower_bound、upper_bound和equal_range)是對數時間的。
62 我會簡單地說明count和 find算法都用相等來搜索,
????? 而binary_search、lower_bound、upper_bound和equal_range則用等價
63 lower_bound回答這個問題:“它在嗎?如果
是,第一個拷貝在哪里?如果不是,它將在哪里?”
保持比
較函數同步不是火箭發射,但卻是另一個要記住的東西,而且我想你已經有很多需要你記的東西了。
64 使用equal_range。equal_range返回一對迭代器,第一個等于lower_bound返回的迭代
器,第二個等于upper_bound返回的(也就是,等價于要搜索值區間的末迭代器的下一個)。因此,
equal_range,返回了一對劃分出了和你要搜索的值等價的區間的迭代器。一個名字很好的算法,不是嗎?
65 通常我們有一個容器,而不是一個區間。在這種情況下,我們必須區別序列和關聯容器。對于標準的序列容器(vector、string、deque和list),你
應該遵循我在本條款提出的建議,使用容器的begin和end迭代器來劃分出區間。
這種情況對標準關聯容器(set、multiset、map和multimap)來說是不同的,因為它們提供了搜索的成員函
數,它們往往是比用STL算法更好的選擇。條款44詳細說明了為什么它們是更好的選擇,簡要地說,是因為
它們更快行為更自然。幸運的是,成員函數通常和相應的算法有同樣的名字,所以前面的討論推薦你使用的
算法count、find、equal_range、lower_bound或upper_bound,在搜索關聯容器時你都可以簡單的用同名的成員
函數來代替。
調用binary_search的策略不同,因為這個算法沒有提供對應的成員函數。要測試在set或map中是否存在某個
值,使用count的慣用方法來對成員進行檢測:
。。。。
要測試某個值在multiset或multimap中是否存在,find往往比count好,因為一旦找到等于期望值的單個對象,
find就可以停下了,而count,在最遭的情況下,必須檢測容器里的每一個對象。(對于set和map,這不是問
題,因為set不允許重復的值,而map不允許重復的鍵。)
但是,count給關聯容器計數是可靠的。特別,它比調用equal_range然后應用distance到結果迭代器更好。首
先,它更清晰:count 意味著“計數”。第二,它更簡單;不用建立一對迭代器然后把它的組成(譯注:就
條款45:注意count、find、binary_search、lower_bound、upper_bound和equal_range的區別
是first和second)傳給distance。第三,它可能更快一點。
你想知道的
使用的算法使用的成員函數
在無序區間在有序區間在set或map上在multiset或multimap上
期望值是否存在? find binary_search count find
期望值是否存在?
如果有,第一個等
于這個值的對象在
哪里?
find equal_range find find或lower_bound(參見下面)
第一個不在期望值
之前的對象在哪
里?
find_if lower_bound lower_bound lower_bound
第一個在期望值之
后的對象在哪里?
find_if upper_bound upper_bound upper_bound
有多少對象等于期
望值?
count equal_range,然后distance count count
等于期望值的所有
對象在哪里?
find(迭代) equal_range equal_range equal_range
66 把函數對象作為算法的參數所帶來的不僅是巨大的效率提升。在讓你的代碼可以編譯方面,它們也更穩健。
當然,真函數很有用,但是當涉及有效的STL編程時,函數對象經常更有用。
? 【他們可能會內聯,而普通函數是函數指針,每次的指針調用】
?
67 寫可讀性高的代碼
68 在這里,它叫做_Tree,但我知道的其他實現使用__tree或__rb_tree,后者反映出
使用紅-黑樹——在STL實現中最常使用的平衡樹類型。
?
轉載于:https://www.cnblogs.com/lijinping/p/6170317.html
總結
以上是生活随笔為你收集整理的Effective stl---笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我之我见:samba共享
- 下一篇: 燕十三的剑(一)