Effective STL 条款30
http://blog.csdn.net/amin2001/article/details/8063
STL容器在被添加時(通過insert、push_front、push_back等)自動擴展它們自己來容納新對象。這工作的很好,有些程序員因為這個信仰而被麻痹,認為他們不必擔心要為容器中的對象騰出空間,因為容器自己可以照顧好這些。如果是那樣就好了!當程序員想向容器中插入對象但并沒有告訴STL他們所想的時,問題出現了。這是一個常見的可以自我表現的方法:
int transmogrify(int x); // 這個函數從x// 產生一些新值 vector<int> values; ... // 把數據放入values vector<int> results; // 把transmogrify應用于 transform(values.begin(), values.end(), // values中的每個對象results.end(), // 把這個返回的valuestransmogrify); // 附加到results// 這段代碼有bug!在本例中,transform被告知它的目的區間是從results.end()開始的,所以那就是開始寫在values的每個元素上調用transmogrify的結果的地方。就像所有使用目標區間的算法,transform通過對目標區間的元素賦值的方法寫入結果,transform會把transmogrify應用于values[0]并把結果賦給*results.end()。然后它會把transmogrify應用于value[1]并把結果賦給*(results.end()+1)。那只能帶來災難,因為在*results.end()沒有對象,*(results.end()+1)也沒有!調用transform是錯誤的,因為它會給不存在的對象賦值。(條款50解釋了STL的一個調試實現怎么在運行期檢測這個問題。)犯了這種錯誤的程序員幾乎總是以為他們調用算法的結果能插入目標容器。如果那是你想要發生的,你就必須說出來。STL是一個庫,不是一個精神。在本例中,說“請把transform的結果放入叫做results容器的結尾”的方式是調用back_inserter來產生指定目標區間起點的迭代器:
vector<int> results; // 把transmogrify應用于 transform(values.begin(), values.end(), // values中的每個對象,back_inserter(results), // 在results的結尾transmogrify); // 插入返回的values在內部,back_inserter返回的迭代器會調用push_back,所以你可以在任何提供push_back的容器上使用back_inserter(也就是任何標準序列容器:vector、string、deque和list)。如果你想讓一個算法在容器的前端插入東西,你可以使用front_inserter。在內部,front_inserter利用了push_front,所以front_insert只和提供那個成員函數的容器配合(也就是deque和list):
... // 同上 list<int> results; // results現在是list transform(values.begin(), values.end(), // 在results前端front_inserter(results), // 以反序transmogrify); // 插入transform的結果因為front_inserter用push_front把每個對象添加到results,results中的對象順序會和values中對應的對象順序相反。這也是為什么front_inserter沒有back_inserter那么常用的原因之一。另一個原因是vector不提供push_front,所以front_inserter不能用于vector。
如果你要transform把輸出結果放在results前端,但你也要輸出和values中對應的對象順序相同,只要以相反的順序迭代values:
list<int> results; // 同上 transform(values.rbegin(), values.rend(), // 在results前端front_inserter(results), // 插入transform的結果transmogrify); // 保持相對的對象順序front_inserter讓你強制算法在容器前端插入它們的結果,back_inserter讓你告訴它們把結果放在容器后端,有點驚人的是inserter允許你強制算法把它們的結果插入容器中的任意位置:
vector<int> values; // 同上 ... vector<int> results; // 同上,除了現在 ... // 在調用transform前// results已經有一些數據 transform(values.begin(), values.end(), // 把transmogrify的inserter(results, results.begin() + results.size()/2), // 結果插入transmogrify); // results的中間不管你是否使用了back_inserter、front_inserter或inserter,每次對目的區間的插入只完成一個對象。條款5解釋了對于連續內存容器(vector、string和deque)來說這可能很昂貴,但條款5的建議解決方法(使用區間成員函數)不能應用于使用算法來完成插入的情況。在本例中,transform會對目的區間每次寫入一個值,你無法改變。
當你要插入的容器是vector或string時,你可以通過按照條款14的建議最小化這個代價,預先調用reserve。你仍然要承受每次發生插入時移動元素的開銷,但至少你避免了重新分配容器的內在內存:
vector<int> values; // 同上 vector<int> results; ... results.reserve(results.size() + values.size()); // 確定results至少// 還能裝得下// values.size()個元素 transform(values.begin(), values.end(), // 同上,inserter(results, results.begin() + results.size() / 2),// 但resultstransmogrify); // 沒有任何重新分配操作當使用reserve來提高一連串插入的效率時,總是應該記住reserve只增加容器的容量:容器的大小仍然沒有改變。即使調用完reserve,當你想要讓容器把新元素加入到vector或string時,你也必須對算法使用插入迭代器(比如,從back_inserter、front_inserter或inserter返回的迭代器之一)。
要把這些完全弄清楚,這里有一個提高本條款開始時的那個例子的效率的錯誤方法(就是我們把transmogrify作用于values里的數據的結果附加到results的那個例子):
vector<int> values; // 同上 vector<int> results; ... results.reserve(results.size() + values.size()); // 同上 transform(values.begin(), values.end(), // 寫入transmogrify的結果results.end(), // 到未初始化的內存transmogrify); // 行為未定義!在這段代碼中,transform愉快地試圖對results尾部的原始的、未初始化的內存賦值。通常,這會造成運行期錯誤,因為賦值只在兩個對象之間操作時有意義,而不是在一個對象和一塊原始的比特之間。即使這段代碼碰巧作了你想要它做的事情,results也不會知道transform在它的未使用容量上“創造”的新“對象”。直到results知道之前,它的大小在調用transform后仍然和原來一樣。同樣的,它的end迭代器仍和調用transform前指向同樣的位置。結論呢?使用reserve而沒有用插入迭代器會在算法內部導致未定義行為,也會弄亂容器。
正確地寫這個例子的代碼的方法是使用reserve和插入迭代器:
vector<int> values; // 同上 vector<int> results; results.reserve(results.size() + values.size()); // 同上 transform(values.begin(), values.end(), // 把transmogrify的結果back_inserter(results), // 寫入results的結尾,transmogrify); // 處理時避免了重新分配到目前為止,我都在假設你讓像transform那樣的算法把它們的結果作為新元素插入容器。這是通常的期望,但有時候你要覆蓋現有容器的元素而不是插入新的。當這種情況時,你不需要插入迭代器,但你仍然需要按照本條款的建議來確保你的目的區間足夠大。
比如,假設你讓transform覆蓋results的元素。如果results至少有和values一樣多的元素,那很簡單。如果沒有,你也必須使用resize來確保它有。
vector<int> values; vector<int> results; ... if (results.size() < values.size()){ // 確保results至少results.resize(values.size()); // 和values一樣大 } transform(values.begin(), values.end(), // 覆蓋values.size()個results.begin(), // results的元素transmogrify);或者你可以清空results然后用通常的方式使用插入迭代器:
... results.clear(); // 銷毀results中// 的所有元素 results.reserve(values.size()); // 保留足夠空間 transform(values.begin(), values.end(), // 把transform地返回值pack_inserter(results), // 放入resultstransmogrify);本條款論證了這個主題的很多變化,但我希望你能牢牢記住本質。無論何時你使用一個要求指定目的區間的算法,確保目的區間已經足夠大或者在算法執行時可以增加大小。如果你選擇增加大小,就使用插入迭代器,比如ostream_iterators或從back_inserter、front_inserter或inserter返回的迭代器。這是所有你需要記住的東西。
注意:
copy(ve.begin(),ve.end(),back_inserter(v1));是將ve的數據插入到v1的后面
一:函數模板類
??? 1、一元函數原型
????? template<class _A,class _R>
????? struct unary_function
????? {
??????????? typedef _A argument_type;
??????????? typedef _R result_type;
????? };
??? 2、二元函數原型
????? template<class Arg1,class Arg2,class Result>
????? struct unary_function
????? {
??????????? typedef Arg1 first_argument_type;
??????????? typedef Arg2 Second_argument_type;
??????????? typedef Result result_type;
????? };
??? 3、系統函數對象
????? plus???????????? 返回兩個數的和:a+b????
????? minus??????????? 返回兩個數的差:a-b
????? multiplies?????? 返回兩個數的乘積:a*b
????? divides????????? 返回兩個數的商:a/b
????? mudulus????????? 返回兩個數的模:a%b
????? negate?????????? 返回某個數的相反數:-a
?????
????? equal_to???????? 判斷兩個數是否相等:a==b
????? not_equal_to???? 判斷兩個數是否不等:a!=b
????? greater????????? 判斷第一個數是否大于第二個數:a>b
????? less???????????? 判斷第一個數是否小于第二個數:a<b
????? greate_equal???? 判斷第一個數是否大于等于第二個數:a>=b
????? less_equal?????? 判斷第一個數是否小于等于第二個數:a<=b
?
????? logical_and????? 返回兩個數的邏輯與結果:a&&b
????? logical_or?????? 返回兩個數的邏輯或結果:a||b
????? logical_not????? 返回某個數的邏輯非結果:!a
?
二:通用容器
??? 1、vector
????? vector/vector(int nSize)????? 創建向量容器
????? assign??????????????????????? 對Vector中的元素賦值
????? at??????????????????????????? 返回指定位置的元素
????? back????????????????????????? 返回最末一個元素
????? begin???????????????????????? 返回第一個元素的迭代器
????? capacity????????????????????? 返回vector所能容納的元素數量(在不重新分配內存的情況下)
????? clear???????????????????????? 清空所有元素
????? empty???????????????????????? 判斷Vector是否為空(返回true時為空)
????? end?????????????????????????? 返回最末元素的迭代器(譯注:實指向最末元素的下一個位置)
????? erase???????????????????????? 刪除指定元素
????? front???????????????????????? 返回第一個元素
????? get_allocator???????????????? 返回vector的內存分配器
????? insert??????????????????????? 插入元素到Vector中
????? max_size????????????????????? 返回Vector所能容納元素的最大數量(上限)
????? pop_back????????????????????? 移除最后一個元素
????? push_back???????????????????? 在Vector最后添加一個元素
????? rbegin??????????????????????? 返回Vector尾部的逆迭代器
????? rend????????????????????????? 返回Vector起始的逆迭代器
????? reserve?????????????????????? 設置Vector最小的元素容納數量
????? resize??????????????????????? 改變Vector元素數量的大小
????? size????????????????????????? 返回Vector元素數量的大小
????? swap????????????????????????? 交換兩個Vector
?
??? 2、list
????? assign??????????????????????? 給list賦值
????? back????????????????????????? 返回最后一個元素
????? begin???????????????????????? 返回指向第一個元素的迭代器
????? clear???????????????????????? 刪除所有元素
????? empty???????????????????????? 如果list是空的則返回true
????? end?????????????????????????? 返回末尾的迭代器
????? erase???????????????????????? 刪除一個元素
????? front???????????????????????? 返回第一個元素
????? get_allocator???????????????? 返回list的配置器
????? insert??????????????????????? 插入一個元素到list中
????? max_size????????????????????? 返回list能容納的最大元素數量
????? merge???????????????????????? 合并兩個list
????? pop_back????????????????????? 刪除最后一個元素
????? pop_front???????????????????? 刪除第一個元素
????? push_back???????????????????? 在list的末尾添加一個元素
????? push_front??????????????????? 在list的頭部添加一個元素
????? rbegin??????????????????????? 返回指向第一個元素的逆向迭代器
????? remove??????????????????????? 從list刪除元素
????? remove_if???????????????????? 按指定條件刪除元素
????? rend????????????????????????? 指向list末尾的逆向迭代器
????? resize??????????????????????? 改變list的大小
????? reverse?????????????????????? 把list的元素倒轉
????? size????????????????????????? 返回list中的元素個數?
????? sort????????????????????????? 給list排序
????? splice??????????????????????? 合并兩個list
????? swap????????????????????????? 交換兩個list
????? unique??????????????????????? 刪除list中重復的元素
??? 3、deque
????? push_front????????????????????? 頭部添加一個元素
????? push_back?????????????????????? 尾部添加一個元素
????? insert????????????????????????? 插入一個元素
????? erase?????????????????????????? 刪除一個元素
????? pop_front?????????????????????? 刪除最前一個元素
????? pop_back??????????????????????? 刪除最后一個元素
????? clear?????????????????????????? 清楚所有元素
????? at????????????????????????????? 返回指定位置的元素
??? 4、stack
????? stack<class T,class Container = deque/vector/list<T>>?? 構造棧
????? empty???????????????????????????????????????????????? 堆棧為空則返回真
????? pop?????????????????????????????????????????????????? 移除棧頂元素
????? push????????????????????????????????????????????????? 在棧頂增加元素
????? size????????????????????????????????????????????????? 返回棧中元素數目
????? top?????????????????????????????????????????????????? 返回棧頂元素
??? 5、queue
????? queue<class T,class Container = deque/list<T>>????????? 構造隊列
????? back????????????????????????????????????????????????? 返回最后一個元素
????? empty???????????????????????????????????????????????? 如果隊列空則返回真
????? front???????????????????????????????????????????????? 返回第一個元素
????? pop?????????????????????????????????????????????????? 刪除第一個元素
????? push????????????????????????????????????????????????? 在末尾加入一個元素
????? size????????????????????????????????????????????????? 返回隊列中元素的個數
??? 6、set
????? begin??????????????? 指向set的頭指針
????? clear??????????????? 刪除所有元素
????? count??????????????? 返回某鍵值元素的個數
????? empty??????????????? 返回是否為空
????? end????????????????? 指向set的尾指針
????? erase??????????????? 刪除某位置元素
????? pair<iterator, iterator>equal_range(const key_type& x)???????? 返回一個迭代器對(指向鍵不小于x的第一個元素的迭代器,指向鍵大于x的第一個元素的迭代器)
????? find???????????????? 返回某索引元素指針
????? get_allocator??????? 返回構造函數的一個拷貝
????? pair<iterator,bool>insert(const value_type& x)返回<指向元素x的迭代器,是否插入成功>
????? lower_bound????????? 返回鍵值不小于某值的第一個元素的迭代器
????? max_size???????????? 返回該set可以控制的最大長度
????? rbegin?????????????? 返回反向set的反向頭指針
????? rend???????????????? 返回反響set的反向尾指針
????? resize(size_type Sz, T C=T())????????????????????????????????? 插入或刪除使元素的個數為n,插入的元素為C
??? 7、map
????? map(const Pred& comp=Pred(),const A& al=A())?????????????????????????? 構造函數
????? pair<const_iterator,const_iterator>equal_range(const Key& key)const:?? 返回迭代器中鍵值等于key的迭代指針[fitst,last)
??? 8、迭代器函數
????? back_inserter??????? 返回容器的后插迭代器
????? front_inserter?????? 返回容器的前插迭代器
三:非變異算法
???
??? 1、循環
????? for_each?????????????? 對每個元素執行相同的函數操作
???
??? 2、查詢
????? find?????????????????? 某值第一次出現位置
????? find_if??????????????? 符合某謂詞的第一個元素
????? find_first_of????????? 子序列某元素第一次出現位置
????? adjacent_find????????? 第一次相鄰元素相等的位置
????? find_end?????????????? 子序列最后出現位置
????? search???????????????? 子序列第一次出現位置
????? search_n?????????????? 一個值連續出現n次的位置
??? 3、計數
????? count????????????????? 某值出現的此時
????? count_if?????????????? 與某謂詞匹配的次數
??? 4、比較
????? equal????????????????? 兩個序列對應元素都相同為真
????? mismatch?????????????? 兩個序列相異的第一個元素
四:變異算法
??? 1、變換
????? transform????????????? 將某操作應用于指定范圍的元素
??? 2、填充
????? fill?????????????????? 用給定值填充所有元素
??? 3、生成
????? generate?????????????? 用一操作的結果填充所有元素
??? 4、唯一
????? unique/unique_copy???? 刪除相鄰位置重復的元素
??? 5、反轉
????? reverse/reverse_copy?? 循環移動元素
??? 6、隨機
????? random_shuffle???????? 隨機移動元素
??? 7、劃分
????? partition/stable_paritition 滿足謂詞的元素都放在前面
五:排序及相關操作
??? 1、排序
????? sort???????????????????????? 以很好的平均效率排序
????? stable_sort????????????????? 穩定排序
????? partial_sort???????????????? 局部排序
????? partial_sort_copy??????????? 復制時進行局部排序
??? 2、二分檢索
????? lower_bound????????????????? 大于等于某值第一次出現的迭代器位置
????? upper_bound????????????????? 大于某值第一次出現位置
????? equal_range????????????????? 等于某值迭代器范圍
????? binary_search??????????????? 是否存在某值
??? 3、歸并
????? merge??????????????????????? 歸并兩個迭代器有序序列
????? inplace_merge??????????????? 歸并單個迭代器有序序列
??? 4、有序結構上的集合操作
????? includes???????????????????? 一個序列為另一個序列子集為真
????? set_union??????????????????? 構造兩集合有序并集
????? set_intersection???????????? 構造有序交集
????? set_difference?????????????? 構造有序差集
????? set_symmetric_difference???? 構造有序對稱差
??? 5、堆操作
????? make_heap??????????????????? 從序列構造堆
????? pop_heap???????????????????? 從堆中彈出元素
????? push_heap??????????????????? 加入元素
????? sort_heap??????????????????? 排序
??? 6、最大最小
????? max
????? min
????? min_element
????? max_element
??? 7、詞典比較
????? lexicographical_compare????? 兩個序列按字典序排序
??? 8、排列生成器
????? next_permutation???????????? 按字典序的下一個排序
????? prev_permutation???????????? 按字典序的上一個排序
??? 9、數值算法
????? accumulate?????????????????? 累積求和
????? inner_product??????????????? 內積求和
????? partial_sum????????????????? 創建新序列,每個元素值代表指定范圍內該位置前所有元素之和
????? adjacent_difference????????? 相鄰元素差集
http://www.crackerban.com/?p=1158
總結
以上是生活随笔為你收集整理的Effective STL 条款30的全部內容,希望文章能夠幫你解決所遇到的問題。