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; } 

数组a中有三个10。

为什么数组v包含一个10后,我们删除所有的10与删除function。

你也可以在这里看到编译的输出

其实std::remove不会从容器中删除项目。 从这里引用

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

也就是说, std::remove只与一对迭代器一起工作,并不知道任何有关容器实际上包含的项目。 事实上, std::remove不可能知道底层容器,因为从一对迭代器中找不到迭代器所属的容器是不可能的。 所以std::remove并没有真的删除这些项目, 只是因为它不能实际上从容器中删除项目的唯一方法是调用该容器上的成员函数。

所以,如果你想删除的项目,然后使用擦除删除成语 :

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

擦除删除成语是如此常见和有用的是, std::list添加了另一个名为list::remove成员函数,它产生了和erase-remove成语相同的效果。

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

这意味着,当你使用std::list时,你不需要使用erase-remove idiom。 你可以直接调用它的成员函数list::remove

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

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

顺便说一句,这就是所谓的“删除成语”。

编辑:我是不正确的。 看到评论和纳瓦兹的回答。

因为std::remove实际上并没有缩小容器,它只是将所有元素移动到填充“removed”元素所使用的位置。 例如,如果您有一个序列1 2 3 4 5并使用std::remove删除值2 ,您的序列将看起来像1 3 4 5 5 。 如果你删除值4 ,你会得到1 3 5 5 5 。 序列从来没有被告知要缩短。