为什么std :: whatever :: erase()方法和std :: remove()是一个独立的函数?

时间:2015-02-25 19:35:54

标签: c++ stl

erase()remove()之间的区别是什么?

  • std::whatever::erase - 获取范围迭代器(倒数第一个),并匹配所有元素。
  • std::remove - 获取范围迭代器(first-last)和匹配删除的值。

除此之外,看起来他们做同样的事情。即实际的擦除'或者'删除'两种情况都是一样的(除非我误认为)。那么,为什么其中一个是(矢量,集合,映射等)方法,另一个是自由浮动函数?

注意:

  • 是的,我知道还有一个erase(),它只需要一个迭代器,但你也可以拥有一个具有相同语义的std::remove()

3 个答案:

答案 0 :(得分:7)

删除或删除相同。

erase实际上会从集合中删除项目。

std::remove使集合的大小与它开始时的大小相同,但是会压缩集合中的项目,因此具有您想要删除的值的那些已经被具有其他值的集合中的值覆盖了

换句话说,如果你开始使用1, 2, 1, 3并做了remove(..., 1),那么你最终会得到一个包含2, 3, x, x的集合,其中x表示某些未知值(可能是一个移动的值,所以如果它们是字符串,它们可能会变成空字符串)。

完成后,它会将迭代器返回到第一个x的位置。如果你想从集合中实际删除这些项目,那么你可以调用collection.erase(returned_iterator, collection.end())(又名删除/擦除习语)。

如果你关心为什么事情是这样的,一个原因是std::remove与迭代器一起工作。迭代器允许访问容器中的元素,但不能访问周围容器本身。因此,std::remove不可能从容器中删除元素,即使对于支持该容器的容器(而不是所有容器)也是如此。

答案 1 :(得分:3)

std::remove实际上并没有销毁容器中的元素。相反,它移动"所有元素都满足范围内的特定条件,并返回范围新结束的过去迭代器。

  

通过移动(通过移动分配)来完成移除   范围内的元素以不使用的元素的方式   被删除出现在范围的开头。相对的顺序   保留的元素和物理大小   容器没有变化。 - http://en.cppreference.com/

移动赋值将移动的变量保留为有效但未指定的状态,因此它可能保持不变,也可能不保持不变。

要从容器中实际删除元素,您需要调用erase

这是一个具体的例子:

#include <iostream>
#include <algorithm>
#include <vector>

void printVector( const std::vector<int>& v )
{
    for ( auto i : v ) {
        std::cout << i << ' ';
    }
    std::cout << std::endl;
}

int main()
{
    std::vector<int> v { 0, 1, 2, 1, 3, 4 };

    printVector( v ); // Prints 0 1 2 1 3 4

    // Shift elemnts that aren't to be removed to the beginning of container
    const auto newEnd = std::remove( v.begin(), v.end(), 1 );

    printVector( v ); // Prints 0 2 3 4 * *

    // Erase the unwanted elements
    v.erase( newEnd, v.end() );

    printVector( v ); // Prints 0 2 3 4

    return 0;
}

Live example

答案 2 :(得分:0)

std::remove(和std::remove_if)是一种通用算法,可以(也)应用于数组。无法擦除数组元素。数组的大小是固定的。您只能将数组中的“已擦除”元素移动到其尾部。并且数组没有方法。您只能使用带数组的常规函数​​。

用户定义(标准)容器的方法erase确实会删除容器的元素。此外,这种方法可以无条件地擦除元素。

考虑到要从容器中擦除元素,您需要知道容器的实现细节。所以这解释了为什么擦除被定义为容器的方法。

反过来,标准算法std::removestd::remove_if实现了移动“擦除”元素的通用算法。他们不需要知道它们所应用的容器的实现细节。

除了方法擦除类std::liststd::forward_list也有自己的方法removeremove_if,它们与通用算法std::remove和{{1}相反根据某些条件从列表中删除元素(类似于标准算法std::remove_ifstd::remove)。

考虑以下示例,以查看通用算法std::remove_if与类std::remove的方法remove之间的区别

std::list

程序输出

#include <iostream>
#include <algorithm>
#include <list>

int main() 
{
    std::list<int> l = { 1, 10, 2, 3, 10, 4 };

    std::cout << "size of the list is " << l.size() << std::endl;
    for ( int x : l ) std::cout << x << ' ';
    std::cout << std::endl;     

    std::remove( l.begin(), l.end(), 10 );

    std::cout << "\nsize of the list is " << l.size() << std::endl;
    for ( int x : l ) std::cout << x << ' ';
    std::cout << std::endl;     

    l = { 1, 10, 2, 3, 10, 4 };

    l.remove( 10 );

    std::cout << "\nsize of the list is " << l.size() << std::endl;
    for ( int x : l ) std::cout << x << ' ';
    std::cout << std::endl;     

    return 0;
}