• 令人疑惑的 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)。

    可以使用智能指针。

  • 相关阅读:
    生成更大的陆地 Making A Large Island
    HDU 3342 Legal or Not【拓扑排序】
    POJ 2367 Genealogical tree【拓扑排序】
    CodeForces Round #290 Div.2
    HDU 1010 Tempter of the Bone【DFS】
    HDU 1312 Red and Black【DFS】
    POJ 1664 放苹果【DFS】
    HDU 1587 Flowers【贪心】
    Codeforces Round #289 Div 2
    HDU 1241 Oil Deposits【DFS】
  • 原文地址:https://www.cnblogs.com/jingyg/p/5613303.html
Copyright © 2020-2023  润新知