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

Fra*_*fer 26 c++ stl erase-remove-idiom c++11 c++17

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

但是,在C++中执行此操作的标准方法似乎是以下习惯用法:

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

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

我发现它不仅丑陋而且容易错误使用.很明显,std::remove_if不能改变向量的大小(正如其名称所暗示的那样)因为它只传递了迭代器.但是许多开发人员,包括我自己,在开始时都没有这样做.

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

Ric*_*ges 25

我发现它不仅丑陋而且容易错误使用.

别担心,我们都在一开始就做了.

很明显,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());    
}
Run Code Online (Sandbox Code Playgroud)

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

auto is_negative = [](int x){return x < 0;};
erase_where(ints, is_negative);
Run Code Online (Sandbox Code Playgroud)

要么

erase_where(ints, [](int x){return x < 0;});
Run Code Online (Sandbox Code Playgroud)

  • 去年@Yakk _if是*so*._where是新的黑色. (2认同)

Tem*_*Rex 14

通过该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, ","));
}
Run Code Online (Sandbox Code Playgroud)

打印0,1的实例

  • `std::erase_if` 在 C++20 中存在,在 &lt;vector&gt; 中定义。 (2认同)