使用erase-remove_if成语

时间:2016-08-18 13:42:36

标签: c++ erase-remove-idiom

假设我有std::vector<std::pair<int,Direction>>

我正在尝试使用erase-remove_if惯用法从向量中删除对。

stopPoints.erase(std::remove_if(stopPoints.begin(),
                                stopPoints.end(),
                                [&](const stopPointPair stopPoint)-> bool { return stopPoint.first == 4; }));

我想删除所有将.first值设置为4的对。

在我的例子中,我有成对:

- 4, Up
- 4, Down
- 2, Up
- 6, Up

然而,在我执行erase-remove_if后,我留下了:

- 2, Up
- 6, Up
- 6, Up

我在这里做错了什么?

2 个答案:

答案 0 :(得分:15)

正确的代码是:

stopPoints.erase(std::remove_if(stopPoints.begin(),
                                stopPoints.end(),
                                [&](const stopPointPair stopPoint)-> bool 
                                       { return stopPoint.first == 4; }), 
                 stopPoints.end());

您需要删除从std::remove_if返回到迭代器的范围,而不仅仅是单个元素。

&#34;为什么&#34;

  • std::remove_if在向量内部交换元素,以便将与谓词不匹配的所有元素放到容器的开头

    • 然后返回指向第一个谓词匹配元素的迭代器

    • std::vector::erase需要擦除从返回的迭代器开始到向量的范围,以便删除与谓词匹配的所有元素

更多信息: Erase-remove idiom (Wikipedia)

答案 1 :(得分:7)

方法std::vector::erase有两个重载:

iterator erase( const_iterator pos );
iterator erase( const_iterator first, const_iterator last );

第一个仅删除pos处的元素,而第二个删除范围[first, last)

由于您在调用中忘记了last迭代器,因此第一个版本是通过重载决策选择的,并且您只删除了std::remove_if移动到末尾的第一个版本。你需要这样做:

stopPoints.erase(std::remove_if(stopPoints.begin(),
                                stopPoints.end(),
                                [&](const stopPointPair stopPoint)-> bool { return stopPoint.first == 4; }), 
                 stopPoints.end());

erase-remove 成语的工作方式如下:假设您有一个向量{2, 4, 3, 6, 4},并且要删除4

std::vector<int> vec{2, 4, 3, 6, 4};
auto it = std::remove(vec.begin(), vec.end(), 4);

通过将&#34;删除&#34;将矢量转换为{2, 3, 6, A, B}。最后的值(末尾的值AB未指定(就好像值已移动),这就是为什么你有6个你的例子)并将迭代器返回A(第一个&#34;删除&#34;值)。

如果你这样做:

vec.erase(it)

选择std::vector::erase的第一个重载,您只删除it处的值,即A并获取{2, 3, 6, B}

添加第二个参数:

vec.erase(it, vec.end())

选择第二个重载,并删除itvec.end()之间的值,以便删除AB