当前位置: 首页 > news >正文

C++11 lambda表达式使用讲解

文章目录

  • C++11 lambda表达式使用讲解
    • 一、lambda 表达式的基本语法
    • 二、lambda 表达式的使用示例
      • 2.1 基础用法(无捕获、无参数)
      • 2.2 捕获外部变量
        • 2.2.1 捕获列表
        • 2.2.2 捕获的三种主要方式
          • (1)显式捕获(按值/按引用)
          • (2)隐式捕获
          • (3)混合捕获(显式 + 隐式)
        • 2.2.3 特殊变量的捕获规则
        • 2.2.4 `mutable` 修饰符与捕获的可修改性
      • 2.3 带参数和返回值
      • 2.4 作为参数传递(回调函数)
      • 2.5 作为智能指针的删除器
    • 三、lambda 表达式的核心特性总结
        • 与普通函数的区别

C++11 lambda表达式使用讲解

在 C++11 中,lambda 表达式是一种匿名函数(没有名称的函数),可以在需要函数的地方直接定义和使用,主要用于简化代码,尤其是在需要传递简短函数作为参数的场景(如算法回调、智能指针删除器等)。

一、lambda 表达式的基本语法

lambda 表达式的完整语法格式如下:

[capture-list](parameters) mutable noexcept -> return-type {// 函数体
}

lambda 表达式本质是一个匿名函数对象,跟普通函数不同的是他可以定义在函数内部。 lambda 表达式语法使用层而言没有类型,所以我们一般是用auto或者模板参数定义的对象去接收 lambda 对象。

各部分含义

  1. [capture-list](捕获列表)
    用于捕获 lambda 外部的变量,使其能在函数体内使用。这是 lambda 与普通函数的核心区别(普通函数无法直接访问外部局部变量)。

    • 常见用法:
      • []:不捕获任何外部变量。
      • [=]:按值捕获所有外部变量(拷贝一份,函数体内不能修改)。
      • [&]:按引用捕获所有外部变量(可修改,需注意变量生命周期)。
      • [x, &y]:按值捕获 x,按引用捕获 y
  2. (parameters)(参数列表)
    与普通函数的参数列表一致,用于接收传入的参数。如果没有参数,可省略括号(但建议保留以明确意图)。

  3. mutable(可选)
    默认情况下,按值捕获的变量在 lambda 内是只读的。加上 mutable 后,允许修改按值捕获的变量(但修改不会影响外部原变量)。

  4. noexcept(可选)
    声明 lambda 不会抛出异常,用于优化和明确接口。

  5. -> return-type(返回值类型)
    返回值类型,用追踪返回类型形式声明函数的返回值类型,没有返回值时此 部分可省略。一般返回值类型明确情况下,也可省略,由编译器对返回类型进行推导。

  6. { ... }(函数体)
    包含具体的执行逻辑,与普通函数体相同。

二、lambda 表达式的使用示例

2.1 基础用法(无捕获、无参数)

#include <iostream>int main() {// 定义一个简单的lambda表达式(打印信息)auto printHello = []() {std::cout << "Hello, lambda!" << std::endl;};// 调用lambda表达式(像调用函数一样)printHello();  // 输出:Hello, lambda!return 0;
}
  • auto 用于自动推导 lambda 的类型(lambda 类型是编译器生成的匿名类型,无法显式写出)。
  • 调用方式与普通函数相同:printHello()

2.2 捕获外部变量

2.2.1 捕获列表

lambda 表达式的捕获列表是 lambda 能够访问外部作用域变量的关键机制,lambda 表达式默认只能直接使用自身函数体和参数中的变量。如果要使用外层作用域(比如定义 lambda 的函数中的局部变量)的变量,就必须通过“捕获列表”明确声明要捕获哪些外部变量。

2.2.2 捕获的三种主要方式
(1)显式捕获(按值/按引用)
  • 格式:在捕获列表中显式列出变量名,用逗号分隔。
    • 按值捕获:直接写变量名(如 [x, y]),会拷贝一份外部变量的值到 lambda 内部,lambda 内修改该拷贝不影响外部原变量。
    • **按引用捕获:**变量名前加 &(如 [&z]),lambda 内部通过引用访问外部变量,修改会直接影响外部原变量。
  • 示例:
    int a = 0, b = 1;
    // 显式按值捕获a,按引用捕获b
    auto func = [a, &b]() {// a++;  // 错误:按值捕获的变量默认是const,不能修改b++;    // 正确:按引用捕获,可修改外部breturn a + b;
    };
    
(2)隐式捕获

无需显式列出变量名,编译器会自动捕获 lambda 内部使用的外部变量。

  • **隐式按值捕获:**捕获列表写 [=],lambda 内使用的所有外部变量都按值捕获(拷贝)。
  • **隐式按引用捕获:**捕获列表写 [&],lambda 内使用的所有外部变量都按引用捕获。
  • 示例(对应图中代码片段思路):
    int a = 0, b = 1, c = 2;
    // 隐式按值捕获所有用到的外部变量(a、b、c)
    auto func = [=]() {return a + b + c;  // 使用a、b、c的拷贝值
    };
    
(3)混合捕获(显式 + 隐式)

同时使用显式和隐式捕获,需遵循规则:

  • 若第一个元素是 &(如 [&, x, y]):表示除显式列出的变量外,其他用到的外部变量隐式按引用捕获;显式列出的 xy 需按值捕获。
  • 若第一个元素是 =(如 [=, &x, &y]):表示除显式列出的变量外,其他用到的外部变量隐式按值捕获;显式列出的 xy 需按引用捕获。
  • 示例(对应图中代码片段思路):
    int a = 0, b = 1, c = 2, d = 3;
    // 混合捕获:隐式按引用捕获其他变量,显式按值捕获a、b
    auto func = [&, a, b]() {// a++;  // 错误:a是按值捕获的拷贝,且默认const// b++;  // 错误:同理c++;    // 正确:c是隐式按引用捕获d++;    // 正确:d是隐式按引用捕获return a + b + c + d;
    };
    
2.2.3 特殊变量的捕获规则
  • 全局变量、静态局部变量:无需捕获,lambda 可直接使用(因为它们的作用域是全局或整个函数,生命周期足够长)。如果 lambda 定义在全局作用域,捕获列表必须为空(没有局部变量可捕获)。
  • 局部变量:只能捕获 lambda 定义位置之前的局部变量,之后定义的局部变量无法捕获。
2.2.4 mutable 修饰符与捕获的可修改性

默认情况下,按值捕获的变量在 lambda 内部是 const 修饰的(即只读)。如果需要修改按值捕获的变量,需在参数列表后加 mutable

  • 作用:移除按值捕获变量的 const 属性,允许在 lambda 内部修改。
  • 注意:修改的是“拷贝的副本”,不会影响外部原变量。且加 mutable 后,即使参数列表为空,也不能省略参数列表的括号(如 []() mutable { ... })。
  • 示例(对应图中代码片段思路):
    int a = 0, b = 1, c = 2, d = 3;
    auto func = [=]() mutable {a++;  // 允许修改(修改的是拷贝)b++;c++;d++;return a + b + c + d;
    };
    func();
    // 外部a、b、c、d的值不变,因为修改的是lambda内的拷贝
    cout << a << " " << b << " " << c << " " << d << endl;
    

2.3 带参数和返回值

#include <iostream>int main() {// 带参数的lambda(计算两数之和)auto add = [](int x, int y) -> int {return x + y;};// 编译器可自动推导返回类型,简化写法auto multiply = [](int x, int y) {return x * y;  // 自动推导返回类型为int};std::cout << add(2, 3) << std::endl;      // 输出:5std::cout << multiply(2, 3) << std::endl; // 输出:6return 0;
}

2.4 作为参数传递(回调函数)

lambda 最常用的场景是作为算法或函数的参数(如标准库算法 std::for_each):

#include <iostream>
#include <vector>
#include <algorithm>int main() {std::vector<int> nums = {1, 2, 3, 4, 5};// 用lambda作为回调,打印所有元素std::for_each(nums.begin(), nums.end(), [](int x) {std::cout << x << " ";});  // 输出:1 2 3 4 5return 0;
}

2.5 作为智能指针的删除器

在之前的智能指针代码中,lambda 被用作删除器,简化自定义释放逻辑:

// 用lambda作为删除器,释放数组
auto delArrLambda = [](Date* ptr) {std::cout << "lambda: 释放数组" << std::endl;delete[] ptr;
};
std::unique_ptr<Date, decltype(delArrLambda)> up4(new Date[3], delArrLambda);

三、lambda 表达式的核心特性总结

  1. 匿名性:lambda 没有名称,通常通过 auto 变量接收后使用,或直接作为参数传递。
  2. 捕获机制:通过 [capture-list] 灵活捕获外部变量,解决了普通函数无法直接访问局部变量的问题。
  3. 简洁性:对于简短的函数逻辑,无需单独定义函数,直接在使用处编写,减少代码跳转。
  4. 类型唯一性:每个 lambda 表达式的类型都是编译器生成的唯一匿名类型,无法显式声明,只能用 autostd::function 存储。
与普通函数的区别
特性lambda 表达式普通函数
名称匿名(无名称)有明确名称
外部变量访问通过捕获列表灵活访问只能访问全局变量或静态变量
类型编译器生成的匿名类型函数类型(可通过函数指针引用)
用途短期使用(如回调、局部逻辑)长期复用、跨范围调用
        | 有明确名称                     |

| 外部变量访问 | 通过捕获列表灵活访问 | 只能访问全局变量或静态变量 |
| 类型 | 编译器生成的匿名类型 | 函数类型(可通过函数指针引用) |
| 用途 | 短期使用(如回调、局部逻辑) | 长期复用、跨范围调用 |

http://www.dtcms.com/a/339121.html

相关文章:

  • string 题目练习 过程分析 具体代码
  • leetcode_239 滑动窗口最大值
  • 本地部署消息中间件 Weblogic 并实现外部访问
  • 2025年9月计算机二级MySQL题库及wampserver2.2e下载安装教程
  • 解决linux中磁盘爆满(准确说是文件系统爆满)导致mysql启动失败的问题——对文件系统进行扩容
  • Chrome 插件开发实战技术文章大纲
  • 前端国际化(i18n)解决方案深度比较
  • C#项目集成海康SDK指南:从搭建环境到实现视频预览、录制、截屏
  • 从H.264到AV1:音视频技术演进与模块化SDK架构全解析
  • ComfyUI部署Wan2.2,开放API,文生视频与图生视频
  • 基于Python的宠物服务管理系统 Python+Django+Vue.js
  • 农村污水处理行业物联网解决方案
  • Vue3 el-table实现 将子表字段动态显示在主表行尾
  • GaussDB 中 alter default privileges 的使用示例
  • 鱼骨图图片制作全指南:使用工具推荐 + 行业案例
  • Python实战:SEO优化自动化工具开发指南
  • 大数据毕业设计选题推荐:护肤品店铺运营数据可视化分析系统详解
  • Android面试指南(三)
  • 在Excel和WPS表格中为多个数字同时加上相同的数值
  • 从接口自动化测试框架设计到开发(三)主流程封装、返回数据写入excel
  • 【iOS】内存管理
  • 如何在 Ubuntu Linux 上安装 RPM 软件包
  • 在 Windows 上使用 Kind 创建本地 Kubernetes 集群并集成Traefik 进行负载均衡
  • 2025年8月16日(星期六):雨骑古莲村游记
  • [优选算法专题二——找到字符串中所有字母异位词]
  • 网络间的通用语言TCP/IP-网络中的通用规则4
  • Java网络编程:TCP与UDP通信实现及网络编程基础
  • C语言—指针(针对小白版)
  • 算法学习day19----博弈论模型--取石子游戏(Python)
  • 懒加载机制实现子模块按需动态导入