C++ 向量的std::删除和擦除之间的差异?

C++ 向量的std::删除和擦除之间的差异?,c++,vector,stl,C++,Vector,Stl,我有一个疑问,我想在头脑中澄清一下。我知道std::vector在erase和std::remove之间的不同行为,其中第一个从向量中物理删除一个元素,减小了大小,而另一个只是移动一个元素,使容量保持不变 这仅仅是为了提高效率吗?通过使用擦除,std::vector中的所有元素将移位1,导致大量副本std::remove只执行“逻辑”删除,并通过移动对象使向量保持不变。如果物体很重,这种差异可能很重要,对吧?是的,这就是它的要点。请注意,erase也受其他性能特征不同的标准容器的支持(例如为O(

我有一个疑问,我想在头脑中澄清一下。我知道
std::vector
erase
std::remove
之间的不同行为,其中第一个从向量中物理删除一个元素,减小了大小,而另一个只是移动一个元素,使容量保持不变


这仅仅是为了提高效率吗?通过使用
擦除
,std::vector中的所有元素将移位1,导致大量副本
std::remove
只执行“逻辑”删除,并通过移动对象使向量保持不变。如果物体很重,这种差异可能很重要,对吧?

是的,这就是它的要点。请注意,
erase
也受其他性能特征不同的标准容器的支持(例如为O(1)),而
std::remove
与容器无关,可用于任何类型的(因此也可用于裸阵列).

std::remove
是STL中的一种算法,它与容器无关。它需要一些概念,没错,但它也被设计用于C数组,这些数组的大小是静态的。

我认为这与需要直接访问向量本身才能调整大小有关。remove只能访问迭代器,因此它无法告诉向量“嘿,你现在拥有的元素更少了”


请参见yves Baumes关于std::remove为何如此设计的答案。

std::remove
只返回一个新的
end()
迭代器,指向最后一个未删除的元素(从返回值到
end()的项数)
将匹配要删除的项目数量,但不能保证它们的值与您要删除的项目的值相同-它们处于有效但未指定的状态)。这样做的目的是使它可以用于多种容器类型(基本上是
ForwardIterator
可以迭代的任何容器类型)

std::vector::erase
在调整大小后实际设置新的
end()
迭代器。这是因为
vector
的方法实际上知道如何调整它的迭代器(同样可以通过
std::list::erase
std::deque::erase
,等等来完成)


remove
组织给定容器以移除不需要的对象。容器的擦除函数实际上以容器需要的方式处理“删除”操作。这就是为什么它们是分开的。

有点像。诸如remove之类的算法在迭代器(表示集合中的元素的抽象)上工作,迭代器不一定知道它们操作的是哪种类型的集合,因此无法调用集合中的成员来执行实际的移除

这很好,因为它允许算法在任何容器上以及整个集合的子集范围上通用地工作


此外,正如您所说,为了提高性能,如果您只需要访问逻辑结束位置以传递给另一个算法,那么可能不需要实际删除(和销毁)元素。

标准库算法对序列进行操作。序列由一对迭代器定义;第一个点位于序列中的第一个元素,第二个点位于序列末尾的一个点。这就是全部;算法不关心序列从何而来

标准库容器保存数据值,并提供一对迭代器,用于指定算法使用的序列。它们还提供成员函数,通过利用容器的内部数据结构,成员函数可以更有效地执行与算法相同的操作

这仅仅是为了提高效率吗?通过使用erase,std::vector中的所有元素将移位1,从而导致大量副本;remove只执行一个“逻辑”删除,并通过移动对象使向量保持不变。如果物体很重,那差别就很重要了,对吧

使用这个成语的原因正是这样。在性能上有好处,但在单次擦除的情况下没有好处。关键在于是否需要从向量中删除多个元素。在这种情况下,
std::remove
只会将每个未删除的元素复制一次到其最终位置,而
vector::erase
方法会将所有元素从该位置移动到末尾多次。考虑:

std::vector<int> v{ 1, 2, 3, 4, 5 };
// remove all elements < 5

这一行代码将过滤掉标准输入中的所有偶数,并将其转储到标准输出,而无需将所有数字加载到容器中的内存中。这是拆分的优点,缺点是算法不能修改容器本身,只能修改迭代器引用的值。

@larsmans,你错了。OP是正确的-有一个
std::remove
template函数,它执行OP所说的操作。@larsmans不正确
std::remove
是一种将集合中的元素标记为已删除的算法。请参阅Scott Meyers的“项目32”,有效STL,Addison Wesley,2001年,第139-143页。“将所有已删除的项目移动到容器末尾后”-std::remove不会这样做。从返回位置开始的末尾元素处于未指定状态。由于
remove
基本上是将要删除的元素与不将要删除的元素交换,因此返回到
end()
的位置是将要删除的所有元素(并且仍然处于有效状态),但是你是对的-不能保证它们“匹配”被交换出去的元素。我要澄清一下。@ZacHowland:现在最大的区别是在C++11中,
std::remove
允许使用移动赋值,这将导致范围[result,end())被删除
std::remove_copy_if(std::istream_iterator<int>(std::cin),
                    std::istream_iterator<int>(),
                    std::ostream_iterator<int>(std::cout, " "),
                    [](int x) { return !(x%2); } // is even
                    );