C++ lambda使用方法和捕获形式

时间:2025-03-14 17:56:51

一、lambda优点

  • 减少命名烦恼
  • 支持泛型编程

二、lambda什么时候用?

  • 简单、使用频率低的操作
    lambda可以理解为一个未命名的内联函数,内联函数的语句应该足够简单,否则会影响效率。两种情况最好使用函数而不是lambda表达式,第一种语句较复杂、多;第二种则是调用频繁。
  • 解除算法特定谓词限制
    一些算法要求可调用对象必须为特定谓词(find_if接受单一参数谓词),使用捕获列表可以降低谓词元数

三、lambda的定义

定义一个lambda等效于定义一个新的未命名类类型,向一个函数传递lambda也就是传递一个lambda对象,使用auto定义变量等效于定义了对应的对象。格式如下:

[capture_list](parameter_list)->return type{fucntion body}

函数体内部可以无条件使用外部的全局变量、作用域内的静态变量,需要捕获才能使用外部局部变量,捕获的变量放在中括号内[我是外部局部变量],和函数参数一样,捕获变量类型可以是引用或者值捕获。值捕获的变量是不能在函数内进行修改的,这是因为:

  • 结果上看,值捕获的变量即使修改了也无法输出
  • 效率上看,值捕获的变量应该设置为常量(事实上也是)以提高效率

事实上,值传递在函数上常见,从结果上看,虽然起不到任何作用,但是我可以复用这个空间。所以,lambda表达式在函数体前加入关键字mutable去掉常量属性。

为了简洁,如果表达式参数列表为空,小括号可省略。

ff = [i]() {i *= 2; };//not allow
ff = [i]() mutable{i *= 2; };//allow

如果捕获的变量较多,捕获列表将会相当冗长。因此C++提供了隐式捕获的符号,它代表着没有显式捕获的所有变量的默认行为,用符号=没有特别声明的一律按值捕获形式,用符号&表示没有特殊声明的一律按照引用捕获。

  • parameter_list:参数列表;

  • return type:返回类型;

  • function boby:函数体。

捕获形式 含义
[] 空捕获(全局和局部静态仍然可见)
[names] 一个逗号分隔的捕获变量列表
& 隐式引用捕获,引用捕获所有外部变量
= 隐式值捕获,值捕获所有外部变量
[&,identifier_list] 除了identifier_list外的所有外部变量都为引用
[=,identifier_list] 除了identifier_list外的所有外部变量都为值

注意事项

  • 尽可能减少捕获量,减少出错的可能;
  • 捕获指向性的对象(指针、迭代器和引用)应该特别注意指向对象是否存在;
  • 值捕获是快照,引用捕获是地址;
  • lambda有返回值。函数体内没有return默认返回void;单个return出口,lambda自行推断(不用自己写返回类型);多个return出口,加上-->return type
  • this指针,是一个low-level属性的指针,因此不能引用捕获,只能值捕获。
  • this指针,你可以使用[=]或者[this]来捕获,[*this]在C++17后可以使用

四、lambda调用

使用调用运算符()

五、lambda引用捕获和值捕获的捕获时刻

引用捕获在调用时进行捕获,而值捕获则是在定义之时进行捕获。

int main()
{
    int a=22;
    auto f=[a](){cout<<a<<endl; };//值捕获,网页快照,内容不变。
    auto ff=[&a]{cout<<a<<endl;};//引用捕获,访问地址,内容会调整。
    f();
    
    a++;
    
    ff();
    f();
    
}

输出结果分别是:22 23 22


[1]《C++ primer 5th》
[2] 你为什么要用lambda表达式?理解它你就知道了
[3] [C++ 11 Lambda表达式] /DswCnblog/p/
[4] 全局变量和静态变量都不需要捕获,因为对函数体可见。类成员也需要捕获。