令人疑惑的 std::remove 算法


摘自《Effective STL》第32條

remove的聲明:

1 template<class ForwardIterator, class T>
2 ForwardIterator remove(ForwardIterator first, ForwardIterator last, const T& value);

如同所有的算法一樣,remove 也需要一對迭代器來指定所要進行操作的元素區間。它並不接受容器作為參數,所以 remove 並不知道這些元素被存放在哪個容器中。並且,remove 也並不能從迭代器推知對應的容器和容器類型。

唯一可以從容器中刪除元素的方法是調用容器的成員函數 erase (list有幾個可以刪除元素的成員函數,但是沒有命名為 erase)。remove 算法並不知道它操作的元素的所在容器,所以不可能從容器中刪除元素。

 1 #include <iostream>
 2 #include <memory>
 3 #include <vector>
 4 #include <algorithm>
 5 
 6 using namespace std;
 7 
 8 int main()
 9 {
10     vector<int> c = {1,2,3,4,5,6,7,8,9,1};
11     cout << "size : " << c.size() << endl;
12 
13     remove(c.begin(), c.end(), 1);
14     cout << "size : " << c.size() << endl;
15     
16 }

執行后顯示:

size : 10
size : 10

使用 remove 后,容器中的元素並沒有減少。

remove 到底做了什么?

簡而言之,remove 移動了區間中的元素。其結果是,“需要被刪除”的元素被移到了區間的尾部。它返回一個迭代器,指向第一個“需要被刪除”的元素。

調用 remove 之前,c 的布局如下:

調用 remove 之后:

vector<int>::iterator newEnd(remove(c.begin(), c.end(), 1));

c 的布局如下

你會發現最后兩個元素的值沒有發生變化。。。

這個是 remove 算法的附帶結果。在內部,remove 遍歷整個區間,用需要保留的元素的值覆蓋掉那些要被刪除的元素的值。這種覆蓋是通過對那些需要被覆蓋的元素的賦值來完成的。

 

因此,要想刪除這些元素,必須調用區間形式的 erase。

還用兩個類似的算法:remove_if  和 unique。都需要在調用 remove_if 和 unique 后調用 erase。

其中 list 的調用是不一致的,list::remove 會真正刪除元素(並且比使用 erase-remove 習慣用法更加高效),list::unique 也會真正刪除元素(並且比使用 erase-unique 更加高效)

 

注意:當容器中存放的是指向動態分配的對象的指針時,應該避免使用 remove 和類似的算法(remove_if 和 unique)。

可以使用智能指針。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM