有没有更好的替代 std::remove_if 从向量中删除元素的方法?

Posted

技术标签:

【中文标题】有没有更好的替代 std::remove_if 从向量中删除元素的方法?【英文标题】:Is there a better alternative to std::remove_if to remove elements from a vector? 【发布时间】:2016-07-22 22:15:20 【问题描述】:

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 无法更改向量的大小(正如其名称所暗示的那样),因为它只会传递迭代器。但包括我自己在内的许多开发人员一开始并没有意识到这一点。

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

【问题讨论】:

与往常一样,如果它变得复杂,请将其包装在(模板)函数中。 @KarolyHorvath:是的,但这是一项很常见的任务。我不想为它编写自己的函数。这属于标准库,就像其他语言一样。 是的,当然,祈祷或写一份提案,然后等待几年。 掌心. @KarolyHorvath:好吧,在堆栈溢出问题上提出这个问题可能只是第一步。我会说比祈祷更好。 将discard_space() 或remove_space() 添加到C++ 中的字符串类会不会很好?这将为集体 C++ 程序员节省 100 年的时间(浪费)。 【参考方案1】:

我觉得它不仅丑而且容易用错。

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

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

【讨论】:

不是remove_erase_if? ;) @Yakk _if 是 so 去年。 _新的黑色在哪里。 @Yakk 进入 LibFun2 en.cppreference.com/w/cpp/experimental/vector/erase_if auto erase_where compile error 'error: 'erase_where' function uses 'auto' type specifier without trailing return type' 所以我将其更改为 void 方法。 @Jayhello 或将其更改为 decltype(auto)。你用的是哪个编译器?【参考方案2】:

这将很快通过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, ","));

Live Example 打印 0,1

【讨论】:

std::erase_if 在 C++20 中,在 中定义。

以上是关于有没有更好的替代 std::remove_if 从向量中删除元素的方法?的主要内容,如果未能解决你的问题,请参考以下文章

remove_if 中的否定谓词

std::remove_if 将“const type”作为“this”参数传递会丢弃 linux 上的限定符 [重复]

C++ 数组转数字

从满足谓词的无序映射中删除元素

从向量中删除项目

对于 Ruby 应用程序,有没有比 Sanitize 更好的替代方案?