• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            colorful

            zc qq:1337220912

             

            STL的remove函數和list的remove成員函數

            http://www.cnblogs.com/kinuxroot/archive/2013/01/25/stl_remove_problem.html

            今天看書剛剛看的,就記錄下來吧。這可能是老生常談了,權且作為一個警醒的例子吧。

            大家都知道STL有兩個非常重要的組成部分,容器和算法。

            算法就是一個個的函數,通過迭代器和容器關聯在一起,完成一些工作。

            算法和容器的分離為程序設計提供了很大的靈活性,但是也帶來了一些負面效果,下面我講的這個問題就是一個例子。

            STL的算法里有一個remove函數,而list自身也有一個remove函數,功能都是一樣的,移除某一個元素,那我們應該使用哪一個呢?

            看一下下面這段程序

            復制代碼
             1     list<int> numbers;  2   3     for ( int number = 0; number <= 6; number ++ ) {  4         numbers.push_front(number);  5         numbers.push_back(number);  6     }  7   8     copy(numbers.begin(), numbers.end(),  9             ostream_iterator<int>(cout, " ")); 10     cout << endl; 11  12     // remove algorithm will remove element but not erase the element from container 13     // it will return the logical desination of container 14     list<int>::iterator endOfNumbers = remove(numbers.begin(), numbers.end(), 3); 15  16     copy(numbers.begin(), numbers.end(), 17             ostream_iterator<int>(cout, " ")); 18     cout << endl;
            復制代碼

            輸出是什么呢?

            第一行肯定是6 5 4 3 2 1 0 0 1 2 3 4 5 6,那么第二行會輸出什么?

            如果是沒有仔細看過STL的人肯定會認為remove(number.begin(), numbers.end(), 3)會移除所有值為3的元素。所以輸出是:6 5 4 2 1 0 0 1 2 4 5 6。

            但是,我們看一下它真正的輸出:

            6 5 4 2 1 0 0 1 2 4 5 6 5 6

            你可能會非常驚訝,為什么最后會多出5和6兩個數呢?

            我們來講一下remove算法的原理。

            remove算法工作時并不是直接把元素刪除,而是用后面的元素替代前面的元素,也即是說如果我對1234這個序列remove 2,返回的序列是 1344(3被復制到2的位置,4被復制到3的位置)。

            這樣上面的例子就好解釋了,那兩個3的元素并沒有被移除,而是用后面的元素覆蓋了前面的元素。多出的那兩個數沒有被移除掉而已。

            那么我們應該如何真正完成移除呢?remove函數會返回一個迭代器,那個迭代器是這個序列的邏輯終點,也即是我代碼里的endOfNumbers,它指向倒數第二個5上。

            于是我們要利用list的erase函數完成元素移除

            numbers.erase(endOfNumbers, numbers.end());

            這樣我們就完成了我們的工作,稍稍有點曲折……

            其實我們可以把這兩步放在一起,比如如果我想接著移除所有值為2的元素

            numbers.erase(remove(numbers.begin(), numbers.end(), 2), numbers.end());

            這樣我們就可以一步到位了。

            但是這樣好么?

            不好。

            大家會發現,remove函數的原理是復制而不是指針的移動(因為函數操縱的是迭代器,而C++的迭代器沒有定義刪除操作),這樣會帶來一個問題:我們使用list是因為它的修改的效率非常高,改變一下指針就可以了。而這里我們復制了元素,如果在vector中,可能還是高效的,因為vector無論如何都要復制,而對于list就不是如此了,會極度降低我們的效率。

            那我們怎么辦呢?

            答案是使用list自己的remove函數

            numbers.remove(1);

            我們可以這樣刪除所有值為1的元素。

            也即是說,如果要刪除list中的元素,我們應該使用list的remove成員函數,而不是remove算法

            小結

            我們都知道,STL是一個效率、復用性、靈活性折衷的產物,其中效率至關重要,所以STL已經禁止了一些效率低的操作(比如list的隨機訪問),而鼓勵你去使用其它的容器。

            但是,在算法中,為了靈活性,STL還是會犧牲一些東西,比如我們這個例子。

            個人覺得,STL作為C++標準庫的一個組成部分,特點和C++本身一模一樣,強大而復雜,有些地方難以理解,很多細節需要學習注意,我們要學會避免陷入某些陷阱之中,比如這個例子就是一個效率陷阱。

            其它更多的陷阱是錯誤處理方面的,STL本身并沒有規定過多的錯誤處理,大部分的錯誤處理都交給了我們,理由很簡單:性能至上,如果一個東西自身沒有錯誤檢查,我們可以包裝一個帶錯誤檢查的類;但是如果這個東西自身就帶了錯誤檢查,那么我們就沒有任何方法提升它的效率了。這也是很多C和C++庫的設計原則。

            所以,很多時候,需要我們深入細節,然后再決定到底怎么做。因為C++就是如此:有很多路可以走,需要我們自己選擇最好的一條路。

            分類: C++

            posted on 2015-10-14 15:50 多彩人生 閱讀(894) 評論(1)  編輯 收藏 引用 所屬分類: boost

            評論

            # re: STL的remove函數和list的remove成員函數[未登錄] 2015-10-14 17:27 chipset

            remove函數并不是真正刪除,而是取代,然后調析構,built-in類型沒有析構函數結果就發現只是向前移動了一下,僅覆蓋而已。
            復制元素并非就一定不高效,對于built-in類型,復制比修改指針高效,畢竟程序設計里小對象比大對象常見的多。再說了,大對象哪里有動不動就拷貝的,那是設計失誤。
            vector的刪除和插入都建議在尾進行,否則效率低下,因此就沒有.pop_front這種貨。  回復  更多評論   

            導航

            統計

            常用鏈接

            留言簿(3)

            隨筆分類

            隨筆檔案

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            久久综合一区二区无码| 亚洲综合久久夜AV | 精品国产综合区久久久久久| 欧美久久久久久午夜精品| 国产69精品久久久久观看软件| 色综合久久久久久久久五月| 国产精品久久亚洲不卡动漫| 综合久久久久久中文字幕亚洲国产国产综合一区首 | 国产精品福利一区二区久久| 久久久受www免费人成| 久久精品国产亚洲AV无码偷窥| 久久播电影网| 久久精品这里热有精品| 久久99精品国产麻豆宅宅| 精品久久久无码中文字幕| AAA级久久久精品无码片| 久久人人爽人人人人片av| 国产精品女同一区二区久久| 色婷婷综合久久久中文字幕| 日本久久久久久久久久| 9191精品国产免费久久| 精品免费久久久久久久| 亚洲va国产va天堂va久久| 色偷偷88欧美精品久久久| 久久综合狠狠色综合伊人| 久久精品无码午夜福利理论片| 久久无码AV一区二区三区| 欧美午夜A∨大片久久| 99久久精品无码一区二区毛片| 国产精品美女久久久久久2018| 久久无码高潮喷水| 久久久久免费精品国产| 欧美精品国产综合久久| 久久久久高潮综合影院| 久久久久国产精品人妻| 久久综合久久美利坚合众国| 少妇久久久久久被弄到高潮| 天天做夜夜做久久做狠狠| 中文成人无码精品久久久不卡| 亚洲欧美国产精品专区久久 | 亚洲国产精品综合久久网络 |