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

C++笔记 Lambda表达式

Lambda表达式是C++11引入的核心特性之一,本质是一种匿名函数,可以捕获作用域内的变量,无需单独定义函数名,就能实现简洁、灵活的代码编写,尤其适合作为回调函数、算法参数(如STL算法)等场景,大幅提升代码可读性和开发效率。

一、Lambda表达式的核心作用

Lambda的核心价值的是“轻量、匿名、可捕获”,解决了传统函数的两个痛点:

  • 无需单独定义函数(尤其是只使用一次的简单逻辑),减少代码冗余;

  • 可以直接捕获当前作用域的变量(局部变量、类成员等),无需通过参数传递,简化逻辑。

最常见的使用场景:配合STL算法(如sort、for_each)、多线程回调(如thread、async)、条件变量的wait条件判断等。

二、Lambda表达式的语法结构(必背)

Lambda的语法格式固定,核心由5部分组成,其中只有“函数体”是必须的,其余部分可根据需求省略:

[捕获列表] (参数列表) mutable noexcept -> 返回值类型 { 函数体; }

1. 各部分详解(从左到右)

(1)捕获列表 [ ]:最关键部分,控制Lambda能否访问外部变量

捕获列表用于指定“Lambda能使用哪些外部变量”,有5种常见写法,必须牢记:

捕获方式

语法

说明

空捕获

[]

不捕获任何外部变量,Lambda内部只能使用自身参数和全局变量

值捕获

[var1, var2]

捕获指定变量(var1、var2),拷贝一份到Lambda内部,默认不可修改(除非加mutable)

引用捕获

[&var1, &var2]

捕获指定变量的引用,Lambda内部操作会直接修改外部变量(注意变量生命周期,避免悬空引用)

值捕获所有变量

[=]

捕获当前作用域所有外部变量,均为值拷贝,默认不可修改

引用捕获所有变量

[&]

捕获当前作用域所有外部变量,均为引用,可修改外部变量

注意:捕获列表不能混合冲突,比如[=, &var]是允许的(所有变量值捕获,唯独var引用捕获),但[&, var]也是允许的(所有变量引用捕获,唯独var值捕获);但[=, &]、[var, =]是错误的。

(2)参数列表 ( ):和普通函数的参数列表一致

用于接收外部传递给Lambda的参数,语法和普通函数完全相同,可省略(当无参数时)。

// 无参数,可省略() auto func1 = [] { cout << "无参数Lambda" << endl; }; // 有参数,和普通函数一致 auto func2 = [](int a, int b) { return a + b; };
(3)mutable:可选,解除值捕获的“只读限制”

值捕获的变量,默认在Lambda内部是“只读”的,无法修改;加上mutable后,允许修改Lambda内部的拷贝(不会影响外部原变量)。

int x = 10; // 错误:值捕获x,默认不可修改 // auto func = [x] { x++; }; // 正确:加mutable,可修改内部拷贝 auto func = [x]() mutable { x++; cout << "内部x:" << x << endl; }; func(); // 输出:内部x:11 cout << "外部x:" << x << endl; // 输出:外部x:10(原变量未变)
(4)noexcept:可选,声明Lambda不会抛出异常

和普通函数的noexcept作用一致,用于告诉编译器,Lambda内部不会抛出异常,可提升性能,尤其在多线程、STL算法中常用。

auto func = [](int a) noexcept { return a * 2; };
(5)返回值类型 -> 类型:可选,编译器可自动推导

如果Lambda函数体只有一条return语句,编译器会自动推导返回值类型,可省略“-> 返回值类型”;如果函数体有多条语句且有返回值,必须显式指定返回值类型。

// 自动推导返回值(int),可省略-> int auto add = [](int a, int b) { return a + b; }; // 必须显式指定返回值,否则编译错误 auto func = [](int a) -> double { if (a > 0) return 1.0; else return 0.5; };
(6)函数体 { }:Lambda的核心逻辑

和普通函数的函数体一致,可编写任意合法的C++代码,可使用捕获的变量、参数列表中的参数。

三、Lambda表达式的基本使用示例

示例1:基础用法(无捕获、有参数、自动推导返回值)

#include <iostream> using namespace std; int main() { // 定义Lambda,计算两个数的和 auto add = [](int a, int b) { return a + b; }; // 调用Lambda,和调用普通函数一样 int result = add(3, 5); cout << "3 + 5 = " << result << endl; // 输出:3 + 5 = 8 return 0; }

示例2:捕获外部变量(值捕获+引用捕获)

#include <iostream> using namespace std; int main() { int x = 10, y = 20; // 值捕获x,引用捕获y auto func = [x, &y]() { // x是值拷贝,不可修改(无mutable);y是引用,可修改 // x++; // 错误:值捕获默认只读 y++; cout << "内部x:" << x << ", 内部y:" << y << endl; }; func(); // 输出:内部x:10, 内部y:21 cout << "外部x:" << x << ", 外部y:" << y << endl; // 输出:外部x:10, 外部y:21 return 0; }

示例3:配合STL算法(最常用场景)

Lambda最常用的场景就是作为STL算法的参数,替代繁琐的函数对象或全局函数。

#include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { vector<int> vec = {3, 1, 4, 1, 5, 9}; // 1. 用Lambda排序(降序) sort(vec.begin(), vec.end(), [](int a, int b) { return a > b; // 降序排序规则 }); // 2. 用Lambda遍历输出 for_each(vec.begin(), vec.end(), [](int val) { cout << val << " "; }); // 输出:9 5 4 3 1 1 return 0; }

示例4:配合多线程(回调函数)

#include <iostream> #include <thread> using namespace std; int main() { int num = 0; // 引用捕获num,在子线程中修改 thread t([&num]() { for (int i = 0; i < 10000; i++) { num++; } }); t.join(); // 等待子线程结束 cout << "num = " << num << endl; // 输出:num = 10000 return 0; }

四、Lambda表达式的注意事项(面试高频)

1. 捕获变量的生命周期问题(重点坑)

引用捕获的变量,Lambda内部持有变量的引用,如果外部变量生命周期结束(比如出作用域销毁),Lambda再访问该引用会导致悬空引用,程序崩溃。

// 错误示例:引用捕获局部变量,变量销毁后Lambda访问悬空引用 auto getFunc() { int x = 10; return [&x]() { cout << x << endl; }; // x是局部变量,出函数销毁 } int main() { auto func = getFunc(); func(); // 崩溃:访问悬空引用 return 0; }

解决方案:如果Lambda要在外部使用,优先使用值捕获(拷贝一份,不受外部变量生命周期影响)。

2. Lambda的本质是“函数对象”

Lambda在编译时会被编译器自动转换为一个“匿名的函数对象”(也叫仿函数),因此Lambda可以赋值给std::function(C++11的函数包装器),方便存储和传递。

#include <functional> #include <iostream> using namespace std; int main() { // Lambda赋值给function function<int(int, int)> add = [](int a, int b) { return a + b; }; cout << add(2, 3) << endl; // 输出:5 return 0; }

3. 捕获列表不能捕获全局变量、静态变量

全局变量、静态变量属于全局作用域,Lambda内部可以直接访问,无需在捕获列表中声明(捕获列表只用于捕获“局部变量”)。

#include <iostream> using namespace std; int g_val = 100; // 全局变量 int main() { static int s_val = 200; // 静态变量 // 无需捕获,直接访问全局变量、静态变量 auto func = []() { cout << "全局变量:" << g_val << endl; cout << "静态变量:" << s_val << endl; }; func(); // 正常输出:全局变量:100 静态变量:200 return 0; }

4. mutable的作用范围

mutable只允许修改“值捕获”的拷贝,不会影响外部原变量;引用捕获的变量,即使不加mutable,也可以修改(因为引用本身就是直接操作原变量)。

5. Lambda不能递归调用(除非借助std::function)

Lambda是匿名函数,自身无法直接调用自己;如果需要递归,必须先将Lambda赋值给std::function,再在函数体中调用该function。

#include <functional> #include <iostream> using namespace std; int main() { // 先声明function,再赋值Lambda function<int(int)> factorial; factorial = [&factorial](int n) { return n == 1 ? 1 : n * factorial(n - 1); }; cout << factorial(5) << endl; // 输出:120(5的阶乘) return 0; }

五、Lambda表达式的核心总结(笔记直接抄)

  1. Lambda是C++11匿名函数,核心语法:[捕获列表](参数列表) mutable noexcept -> 返回值类型 {函数体;}

  2. 捕获列表是核心,分5种:[]、[var]、[&var]、[=]、[&],不可混合冲突;

  3. 值捕获默认只读,需修改内部拷贝加mutable;引用捕获需注意变量生命周期;

  4. 返回值可自动推导(单条return),多条return需显式指定;

  5. 最常用场景:STL算法参数、多线程回调、简单逻辑的临时函数;

  6. 本质是函数对象,可赋值给std::function,支持递归(需借助function)。

Lambda的核心优势是“简洁、灵活”,能大幅简化代码,尤其在需要临时函数的场景中,替代传统函数或函数对象,提升代码可读性和开发效率,是C++多线程、STL开发的必备技能。

http://www.jsqmd.com/news/599117/

相关文章:

  • SEO_详解SEO优化的完整流程与关键步骤
  • 智能家居入门实战:基于STM32的语音+蓝牙双控窗户系统,手把手教你搞定ASR01模块和手机App
  • Xcode16强制升级指南:如何避免Bitcode陷阱并顺利上传App Store Connect
  • 如何用嘎嘎降AI处理医学论文:医学专项降AI操作指南 - 还在做实验的师兄
  • 弯管LRA计算软件(XYZ转LRA)
  • 2026年4月最新:全职作者深度测评8款AI写长篇小说专业工具,谁能打破“吃设定”与“机器味”魔咒?
  • 如何找到适合自己的SEO网站推广公司_SEO网站推广公司的发展趋势如何
  • Adv Sci 复旦大学附属中山医院宋志坚复旦大学上海肿瘤医院黄丹等团队:基于基础模型的多模态深度学习用于结直肠癌不完整模态的预后预测
  • 关于Codex陷阱:AI生成代码的安全雷区的技术
  • 2026年金融学论文降AI工具推荐:市场分析和投资策略部分 - 还在做实验的师兄
  • 【Raspberry PI】Raspberry Pi HEVC (H.265) 硬件解码器
  • OpCore-Simplify:黑苹果智能配置工具如何化繁为简?
  • Java自定义注解创建详解
  • 科研人员必看:如何高效翻译含复杂公式的学术论文?
  • 交通事故处理数字化实践:基于玉溪案例的全流程技术架构设计
  • MATLAB连续潮流程序:IEEE节点标准PV曲线绘制工具,支持14节点与33节点系统,具备分...
  • Java高频面试-如何配置ShardingSphere的数据分片策略?
  • 格行总部招商总监张总,做靠谱长久的随身WiFi创业项目 - 格行官方招商总部
  • 2026年降AI工具价格全面对比:哪款最便宜还好用 - 还在做实验的师兄
  • 新的封面
  • 深入解析 JamTools:免费开源聚合工具的技术架构与跨平台实现
  • 在 Matplotlib 中fontweight一般怎么设置
  • C#基于S7.Net组件实现西门子PLC通信上位机功能说明
  • 从安装到实战:基于快马生成openclaw电商价格监控应用一体化项目
  • 【12.MyBatis源码剖析与架构实战】9.1 ⼆级缓存的原理
  • 2026年了,你还只知道ReLU?一文搞懂神经网络的核心“大脑”
  • 像素特工Ostrakon-VL快速上手:3步搭建零售场景AI视觉分析工具
  • 英飞凌TC387 PMSM永磁同步电机FOC控制Demo及相关文档,W032
  • Python flask django美容美发商城系统
  • 用快马快速构建API限流演示原型,直观理解rate limit exceeded