C++ remove_if函数(遍历元素,将满足条件的元素移动到容器的末尾)(C++一元函数对象)(括号运算符operator())

C++ remove_if函数

C++ 中的 remove_if 函数是用于从容器中删除满足指定条件的元素的算法。它定义在头文件 <algorithm> 中,函数签名如下:

template <class ForwardIterator, class UnaryPredicate>
ForwardIterator remove_if(ForwardIterator first, ForwardIterator last, UnaryPredicate pred);

其中:

  • first 和 last 分别表示容器中要处理的元素的范围,其中 first 指向第一个要处理的元素,last 指向最后一个要处理的元素的下一个位置。这个范围应该是左闭右开区间,即 [first, last)。
  • pred 是一个一元函数对象,用于指定要删除的元素的条件。只有当 pred 返回值为 true 时,才会将该元素删除。也就是说,remove_if 函数会遍历 [first, last) 区间中的所有元素,并将满足条件 pred 的元素移动到容器的末尾,然后返回一个迭代器,指向新的末尾位置。被移动到末尾的元素并没有真正被删除,只是在容器中变成了“未定义”的元素,如果不调用 erase 函数将它们删除,它们仍然会占用容器的空间。

以下是一个示例代码,使用 remove_if 函数从一个 vector 容器中删除所有小于 5 的元素:

(main.cpp)

#include <algorithm>
#include <vector>
#include <iostream>

int main() {
    
    
  std::vector<int> v {
    
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  
  // 使用 lambda 表达式定义要删除的元素的条件
  auto pred = [](int i) {
    
     return i < 5; };
  
  // 调用 remove_if 函数,将满足条件的元素移动到末尾
  auto new_end = std::remove_if(v.begin(), v.end(), pred);
  
  // 调用 erase 函数,将移动到末尾的元素真正删除
  v.erase(new_end, v.end());

  // 输出容器中的元素
  for (auto x : v) {
    
    
    std::cout << x << " ";
  }
  std::cout << std::endl;

  return 0;
}

编译运行:

g++ main.cpp ; ./a.out

结果:

5 6 7 8 9 10

为什么pred 是一个一元函数对象?什么是一元函数对象?

在 C++ 中,函数可以被看做是一种对象,因为函数指针可以被当做指向函数的指针变量来使用,也就是说,函数可以作为参数传递给另一个函数,或者作为另一个函数的返回值。

而一元函数对象就是一种特殊的函数对象,它是一个类或结构体,重载了括号运算符 operator(),使其可以像函数一样被调用。一元函数对象有一个参数,并返回一个值,可以实现一些复杂的逻辑,比如 lambda 表达式就是一种一元函数对象。举个例子:

#include <algorithm>
#include <vector>
#include <iostream>

struct my_predicate {
    
    
  bool operator()(int x) const {
    
    
    return x % 2 == 0;
  }
};

int main() {
    
    
  std::vector<int> v {
    
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  
  // 创建一个 my_predicate 类型的对象 pred
  my_predicate pred;
  
  // 调用 remove_if 函数,将满足条件的元素移动到末尾
  auto new_end = std::remove_if(v.begin(), v.end(), pred);
  
  // 调用 erase 函数,将移动到末尾的元素真正删除
  v.erase(new_end, v.end());

  // 输出容器中的元素
  for (auto x : v) {
    
    
    std::cout << x << " ";
  }
  std::cout << std::endl;

  return 0;
}

编译运行:

g++ main.cpp ; ./a.out

结果:

1 3 5 7 9

在上面的代码中,我们定义了一个名为 my_predicate 的结构体,重载了括号运算符 operator(),使其可以接受一个 int 类型的参数,并返回一个 bool 类型的值。我们将 my_predicate 的一个对象 pred 传递给了 remove_if 函数作为其第三个参数,remove_if 函数会遍历容器中的每一个元素,对于每一个元素,都会调用 pred 对象的括号运算符,传递当前元素的值,判断是否满足删除条件。

总之,一元函数对象就是可以像函数一样被调用的一个对象,其括号运算符重载了一元运算符 (),可以接受一个参数并返回一个值。在使用 remove_if 函数时,我们可以通过定义一个一元函数对象(比如 lambda 表达式或者自定义的结构体),来指定要删除的元素的条件。

什么是括号运算符operator()?

参考文章:C++中operator关键字的用法(重载运算符)

调用 remove_if 函数,是怎么将满足条件的元素移动到末尾的?

std::remove_if 并不会直接删除元素,它只是将满足条件的元素移动到了容器的末尾,并返回一个迭代器,指向移动后的新结尾。

具体来说,std::remove_if 会遍历容器中的每个元素,对于每个元素,判断其是否满足指定的条件。如果该元素满足条件,就将其移动到容器的末尾;如果该元素不满足条件,就不做任何处理。这样,经过 remove_if 操作后,容器中的所有满足条件的元素都被移动到了末尾,而不满足条件的元素则保持原来的顺序。移动后的元素顺序与容器中原有的顺序是一致的,也就是说,先被移动到末尾的元素会位于后面,后被移动到末尾的元素会位于前面

实际上,移动操作是通过 STL 中的 std::move 函数实现的,具体细节可以参考 STL 源码或者 STL 相关的文献资料。

猜你喜欢

转载自blog.csdn.net/Dontla/article/details/129757605