30

从容器或其他容器中删除具有特定属性的元素的任务std::vector适用于函数式实现:为什么要为循环、内存释放和正确移动数据而烦恼?

然而,在 C++ 中执行此操作的标准方法似乎是以下成语:

std::vector<int> ints;
...
ints.erase(
    std::remove_if(ints.begin(), 
                   ints.end(),
                   [](int x){return x < 0;}),
    ints.end());

此示例从整数向量中删除所有小于零的元素。

我发现它不仅丑陋,而且容易使用不正确。很明显,它std::remove_if不能改变向量的大小(正如它的名字所暗示的那样),因为它只会传递迭代器。但是许多开发人员,包括我自己,一开始并没有明白这一点。

那么有没有一种更安全、更有希望更优雅的方式来实现这一目标呢?如果不是,为什么?

4

2 回答 2

27

我发现它不仅丑陋,而且容易使用不正确。

别担心,我们一开始都是这样做的。

很明显,std::remove_if 不能改变向量的大小(正如它的名字所暗示的那样),因为它只会传递迭代器。但是许多开发人员,包括我自己,一开始并没有明白这一点。

相同的。它让每个人都感到困惑。remove_if这么多年前,它可能不应该被调用。事后诸葛亮,嗯?

那么有没有一种更安全、更有希望更优雅的方式来实现这一目标呢?

如果不是,为什么?

因为这是在从容器中删除项目时保持性能的最安全、最优雅的方式,其中删除项目会使迭代器失效。

预计:

有什么我能做的吗?

是的,把这个成语包装成一个函数

template<class Container, class F>
auto erase_where(Container& c, F&& f)
{
    return c.erase(std::remove_if(c.begin(), 
                                  c.end(),
                                  std::forward<F>(f)),
                   c.end());    
}

然后激励示例中的调用变为:

auto is_negative = [](int x){return x < 0;};
erase_where(ints, is_negative);

或者

erase_where(ints, [](int x){return x < 0;});
于 2016-04-03T10:59:03.897 回答
18

这将很快通过std::experimental::erase_if算法在支持 C++17 的编译器中可用:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
#include <experimental/vector>

int main()
{
    std::vector<int> ints { -1, 0, 1 };   
    std::experimental::erase_if(ints, [](int x){
        return x < 0;
    });
    std::copy(ints.begin(), ints.end(), std::ostream_iterator<int>(std::cout, ","));
}

打印 0,1 的实时示例

于 2016-04-05T18:26:29.333 回答