是否有更好的替代std :: remove_if来从向量中删除元素?

时间:2016-04-03 10:55:22

标签: c++ c++11 stl c++17 erase-remove-idiom

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不能改变向量的大小(正如其名称所暗示的那样),因为它只传递迭代器。但是许多开发人员,包括我自己,在开始时都没有这样做。

那么有更安全,更有希望实现这一目标的方式吗?如果没有,为什么?

2 个答案:

答案 0 :(得分:24)

  

我发现它不仅难看而且容易错误使用。

别担心,我们都是在开始时做的。

  

很明显,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;});

答案 1 :(得分:13)

很快就可以通过std::experimental::erase_if算法在C ++ 17就绪编译器中使用它:

/* CSS */
.CssClassJsLoad .JsHide {
    display:none; }
/* For all objects within both of these classes: Do not display.
Remember: the <html>-tag only gets the class "CssClassJsLoad" if JS is present or respectively successfully executed. So if JS is not present, display will be standard as "block" element */
打印0,1

Live Example