STL删除无法按预期工作?

时间:2011-06-23 15:44:48

标签: c++ stl

int main()
{

        const int SIZE = 10;
        int a[SIZE] = {10, 2, 35, 5, 10, 26, 67, 2, 5, 10};
        std::ostream_iterator< int > output(cout, " ");
        std::vector< int > v(a, a + SIZE);
        std::vector< int >::iterator newLastElement;

        cout << "contents of the vector: ";
        std::copy(v.begin(), v.end(), output);

        newLastElement = std::remove(v.begin(), v.end(), 10);
        cout << "\ncontents of the vector after remove: ";
        //std::copy(v.begin(), newLastElement, output); 
                         //this gives the correct result : 2 35 5 26 67 2 5
        std::copy(v.begin(), v.end(), output);
          //this gives a 10 which was supposed to be removed : 2 35 5 26 67 2 5 2 5 10

        cout << endl;
        return 0;
}

阵列中有三个10。

为什么在我们删除带有删除功能的所有10个数组后,数组v包含10。

您还可以看到已编译的输出here

3 个答案:

答案 0 :(得分:27)

实际上std::remove不会从容器中删除该项目。引自here

  

[first, last)范围内移除所有等于value的元素。也就是说,remove返回迭代器new_last,使得范围[first, new_last)不包含等于value的元素。 范围[new_last, last)中的迭代器都仍可解除引用,但它们指向的元素是未指定删除是稳定的,意味着不等于值的元素的相对顺序不变。

也就是说,std::remove仅适用于一对迭代器,并且对实际包含这些项的容器一无所知。实际上,std::remove不可能知道底层容器,因为它无法从一对迭代器中发现迭代器所属的容器。所以std::remove并没有真正删除这些项目,只是因为它不能实际从容器中删除项目的唯一方法是调用该容器上的成员函数。

因此,如果您要删除这些项目,请使用Erase-Remove Idiom

 v.erase(std::remove(v.begin(), v.end(), 10), v.end()); 

erase-remove idiom非常常见且有用的是std::list添加了另一个名为list::remove的成员函数,它产生与erase-remove成语相同的效果。

 std::list<int> l;
 //...
 l.remove(10); //it "actually" removes all elements with value 10!

这意味着,在使用erase-remove时,您不需要使用std::list惯用法。您可以直接调用其成员函数list::remove

答案 1 :(得分:11)

原因是STL算法不会修改序列的大小。 remove,而不是实际删除项目,移动它们并返回迭代器到“新”结束。然后可以将迭代器传递给容器的erase成员函数以实际执行删除:

v.erase(std::remove(v.begin(), v.end(), 10), v.end());

顺便说一句,这被称为“擦除 - 删除成语”。

编辑:我错了。请参阅评论和Nawaz的回答。

答案 2 :(得分:1)

因为std::remove实际上没有收缩容器,所以它只是向下移动所有元素以填充“removed”元素使用的点。例如,如果您有序列1 2 3 4 5并使用std::remove删除值2,则您的序列将显示为1 3 4 5 5。如果您删除了值4,则会获得1 3 5 5 5。在任何时候,序列都不会被告知更短。