C++ Lambda 表达式的本质及原理分析
目录
1.引言
2.Lambda 的本质
3.Lambda 的捕获机制的本质
4.捕获方式的实现与底层原理
5.默认捕获的实现原理
6.捕获 this 的机制
7.捕获的限制与注意事项
8.总结
1.引言
C++ 中的 Lambda 表达式是一种匿名函数,最早在 C++11 引入,用于简化函数对象的定义和使用。它以更简洁的语法提供了强大的功能,但其本质和捕获机制背后有许多值得深究的细节。本文将探讨 Lambda 的本质,以及捕获的底层实现与原理。
2.Lambda 的本质
Lambda 是一个语法糖,本质上是由编译器生成的一个匿名类,该类重载了 operator()(即调用运算符)。在使用 Lambda 表达式时,编译器会隐式生成一个这样的类,并在必要时捕获上下文中的变量。
示例与编译器生成的代码对比
#include <iostream>
#include <functional>int main() {int x = 10;auto lambda = [x](int y) { return x + y; };std::cout << lambda(20) << std::endl; // 输出 30return 0;
}
编译器会将上述 Lambda 转换为类似以下的代码:
#include <iostream>
#include <functional>class LambdaClass {int x;
public:LambdaClass(int x) : x(x) {}int operator()(int y) const {return x + y;}
};int main() {int x = 10;LambdaClass lambda(x);std::cout << lambda(20) << std::endl; // 输出 30return0;
}
可以看到,Lambda 实际上是一个具有捕获变量 x 的函数对象。
3.Lambda 的捕获机制的本质
Lambda 的捕获机制允许其在定义时绑定外部作用域中的变量,以便在 Lambda 内部使用。这一机制本质上是通过捕获变量并存储为匿名类的成员变量来实现的。
捕获的两种方式
1)值捕获(capture by value): 捕获外部变量的副本,保存在 Lambda 的内部。
2)引用捕获(capture by reference): 捕获外部变量的引用,Lambda 内部直接访问外部变量。
4.捕获方式的实现与底层原理
1)值捕获的实现 值捕获会在 Lambda 表达式创建时,将捕获的变量拷贝到匿名类的成员变量中。每次调用 Lambda 时,使用的是捕获时的副本。
#include <iostream>int main() {int x = 10;auto lambda = [x]() { std::cout << x << std::endl; };x = 20;lambda(); // 输出 10,而非 20return 0;
}
编译器生成的代码类似于:
class Lambda {int x; // 保存捕获的副本
public:Lambda(int x) : x(x) {}void operator()() const {std::cout << x << std::endl;}
};
这里,x 是一个副本,与原始变量脱离关系。
2)引用捕获的实现 引用捕获则是将外部变量的引用存储为 Lambda 类的成员变量,调用时直接操作原变量。
#include <iostream>int main() {int x = 10;auto lambda = [&x]() { std::cout << x << std::endl; };x = 20;lambda(); // 输出 20return 0;
}
编译器生成的代码类似于:
class Lambda {int& x; // 保存外部变量的引用
public:Lambda(int& x) : x(x) {}void operator()() const {std::cout << x << std::endl;}
};
可以看到,引用捕获直接存储的是外部变量的引用,Lambda 的调用会影响原变量。
5.默认捕获的实现原理
1)默认值捕获 [=]: 使用 [=] 会默认按值捕获外部作用域的所有变量。
int x = 10, y = 20;
auto lambda = [=]() { return x + y; }; // 默认值捕获 x 和 y
等价于:
class Lambda {int x, y;
public:Lambda(int x, int y) : x(x), y(y) {}int operator()() const {return x + y;}
};
2)默认引用捕获 [&]: 使用 [&] 会默认按引用捕获外部作用域的所有变量。
int x = 10, y = 20;
auto lambda = [&]() { return x + y; }; // 默认引用捕获 x 和 y
等价于:
class Lambda {int& x, & y;
public:Lambda(int& x, int& y) : x(x), y(y) {}int operator()() const {return x + y;}
};
6.捕获 this 的机制
捕获 this 时,实际上是按值捕获了 this 指针,使得 Lambda 可以访问当前对象的成员变量。如果捕获 *this,则表示按值捕获整个对象。
示例:捕获 this
#include <iostream>class MyClass {int data = 42;
public:auto createLambda() {return [this]() { std::cout << data << std::endl; };}
};int main() {MyClass obj;auto lambda = obj.createLambda();lambda(); // 输出 42return0;
}
编译器生成的代码类似于:
class Lambda {MyClass* obj; // 捕获 this 指针
public:Lambda(MyClass* obj) : obj(obj) {}void operator()() const {std::cout << obj->data << std::endl;}
};
7.捕获的限制与注意事项
1)不能捕获动态生成的变量: Lambda 只能捕获作用域中已有的变量,不能捕获运行时动态生成的变量。
2)捕获的生命周期: 引用捕获的变量必须保证 Lambda 的生命周期不超过捕获对象。
3)与 mutable 相关的限制: 捕获的变量默认是不可变的(即 const)。如果需要修改捕获的变量,需要显式添加 mutable。
8.总结
1)Lambda 的本质: 是一个匿名类,其捕获的变量存储为类的成员变量,调用时通过重载的 operator() 实现。
2)捕获的本质: 值捕获是将外部变量的副本存储为类成员,引用捕获是将外部变量的引用存储为类成员。
3)注意事项: 使用 Lambda 时,需要特别关注变量的生命周期和捕获方式,以避免未定义行为。
Lambda 表达式在 C++ 中提供了极大的灵活性和简洁性,特别是在需要定义短小的回调函数或处理算法时。理解并熟练使用 Lambda 表达式可以显著提升代码的可读性和效率。
相关文章:
C++ Lambda 表达式的本质及原理分析
目录 1.引言 2.Lambda 的本质 3.Lambda 的捕获机制的本质 4.捕获方式的实现与底层原理 5.默认捕获的实现原理 6.捕获 this 的机制 7.捕获的限制与注意事项 8.总结 1.引言 C 中的 Lambda 表达式是一种匿名函数,最早在 C11 引入,用于简化函数对象的…...
《多线程基础之条件变量》
【条件变量导读】条件变量是多线程中比较灵活而且容易出错的线程同步手段,比如:虚假唤醒、为啥条件变量要和互斥锁结合使用?windows和linux双平台下,初始化、等待条件变量的api一样吗? 本文将分别为您介绍条件变量在w…...
21款炫酷烟花合集
系列专栏 《Python趣味编程》《C/C趣味编程》《HTML趣味编程》《Java趣味编程》 写在前面 Python、C/C、HTML、Java等4种语言实现18款炫酷烟花的代码。 Python Python烟花① 完整代码:Python动漫烟花(完整代码) Python烟花② 完整…...
智能风控 数据分析 groupby、apply、reset_index组合拳
目录 groupby——分组 本例 apply——对每个分组应用一个函数 等价用法 reset_index——重置索引 使用前编辑 注意事项 groupby必须配合聚合函数、 关于agglist 一些groupby试验 1. groupby对象之后。sum(一个列名) 2. groupby对象…...
Python网络自动化运维---用户交互模块
文章目录 目录 文章目录 前言 实验环境准备 一.input函数 代码分段解析 二.getpass模块 前言 在前面的SSH模块章节中,我们都是将提供SSH服务的设备的账户/密码直接写入到python代码中,这样很容易导致账户/密码泄露,而使用Python中的用户交…...
【JVM】调优
目的: 减少minor gc、full gc的次数,也就是减少STW的时间,因为java虚拟机在做后台垃圾收集线程的时候,会停掉其他线程,专门做垃圾收集,这样会影响网站的性能,以及用户的体验。 调优位置&#x…...
软件测试 —— jmeter(2)
软件测试 —— jmeter(2) HTTP默认请求头(元件)元件作用域和取样器作用域HTTP Cookie管理器同步定时器jmeter插件梯度压测线程组(Stepping Thread Group)参数解析总结 Response Times over TimeActive Thre…...
为什么LabVIEW适合软硬件结合的项目?
LabVIEW是一种基于图形化编程的开发平台,广泛应用于软硬件结合的项目中。其强大的硬件接口支持、实时数据采集能力、并行处理能力和直观的用户界面,使得它成为工业控制、仪器仪表、自动化测试等领域中软硬件系统集成的理想选择。LabVIEW的设计哲学强调模…...
【机器学习】自定义数据集 使用tensorflow框架实现逻辑回归并保存模型,然后保存模型后再加载模型进行预测
一、使用tensorflow框架实现逻辑回归 1. 数据部分: 首先自定义了一个简单的数据集,特征 X 是 100 个随机样本,每个样本一个特征,目标值 y 基于线性关系并添加了噪声。tensorflow框架不需要numpy 数组转换为相应的张量࿰…...
.NET Core缓存
目录 缓存的概念 客户端响应缓存 cache-control 服务器端响应缓存 内存缓存(In-memory cache) 用法 GetOrCreateAsync 缓存过期时间策略 缓存的过期时间 解决方法: 两种过期时间策略: 绝对过期时间 滑动过期时间 两…...
GA-CNN-LSTM-Attention、CNN-LSTM-Attention、GA-CNN-LSTM、CNN-LSTM四模型多变量时序预测一键对比
GA-CNN-LSTM-Attention、CNN-LSTM-Attention、GA-CNN-LSTM、CNN-LSTM四模型多变量时序预测一键对比 目录 GA-CNN-LSTM-Attention、CNN-LSTM-Attention、GA-CNN-LSTM、CNN-LSTM四模型多变量时序预测一键对比预测效果基本介绍程序设计参考资料 预测效果 基本介绍 基于GA-CNN-LST…...
git Bash通过SSH key 登录github的详细步骤
1 问题 通过在windows 终端中的通过git登录github 不再是通过密码登录了,需要本地生成一个密钥,配置到gihub中才能使用 2 步骤 (1)首先配置用户名和邮箱 git config --global user.name "用户名"git config --global…...
《企业应用架构模式》笔记
领域逻辑 表模块和数据集一起工作-> 先查询出一个记录集,再根据数据集生成一个(如合同)对象,然后调用合同对象的方法。 这看起来很想service查询出一个对象,但调用的是对象的方法,这看起来像是充血模型…...
深入理解 C 语言函数指针的高级用法:(void (*) (void *)) _IO_funlockfile
深入理解 C 语言函数指针的高级用法 函数指针是 C 语言中极具威力的特性,广泛用于实现回调、动态函数调用以及灵活的程序设计。然而,复杂的函数指针声明常常让即使是有经验的开发者也感到困惑。本文将从函数指针的基本概念出发,逐步解析复杂…...
【JavaSE】图书管理系统
前言:为了巩固之前学习的java知识点,我们用之前学习的java知识点(方法,数组,类和对象,封装,继承,多态,抽象类,接口)来实现一个简单的图书管理系统…...
【C++数论】880. 索引处的解码字符串|2010
本文涉及知识点 数论:质数、最大公约数、菲蜀定理 LeetCode880. 索引处的解码字符串 给定一个编码字符串 s 。请你找出 解码字符串 并将其写入磁带。解码时,从编码字符串中 每次读取一个字符 ,并采取以下步骤: 如果所读的字符是…...
C++/stack_queue
目录 1.stack 1.1stack的介绍 1.2stack的使用 练习题: 1.3stack的模拟实现 2.queue的介绍和使用 2.1queue的介绍 2.2queue的使用 2.3queue的模拟实现 3.priority_queue的介绍和使用 3.1priority_queue的介绍 3.2priority_queue的使用 欢迎 1.stack 1.1stack…...
浅谈APP之历史股票通过echarts绘图
浅谈APP之历史股票通过echarts绘图 需求描述 今天我们需要做一个简单的历史股票收盘价格通过echarts进行绘图,效果如下: 业务实现 代码框架 代码框架如下: . 依赖包下载 我们通过网站下载自己需要的涉及的图标,勾选之后进…...
Ubuntu 20.04 x64下 编译安装ffmpeg
试验的ffmpeg版本 4.1.3 本文使用的config命令 ./configure --prefixhost --enable-shared --disable-static --disable-doc --enable-postproc --enable-gpl --enable-swscale --enable-nonfree --enable-libfdk-aac --enable-decoderh264 --enable-libx265 --enable-libx…...
【橘子Kibana】Kibana的分析能力Analytics简易分析
一、kibana是啥,能干嘛 我们经常会用es来实现一些关于检索,关于分析的业务。但是es本身并没有UI,我们只能通过调用api来完成一些能力。而kibana就是他的一个外置UI,你完全可以这么理解。 当我们进入kibana的主页的时候你可以看到这样的布局。…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...
云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...
篇章二 论坛系统——系统设计
目录 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 1. 数据库设计 1.1 数据库名: forum db 1.2 表的设计 1.3 编写SQL 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 通过需求分析获得概念类并结合业务实现过程中的技术需要&#x…...
链式法则中 复合函数的推导路径 多变量“信息传递路径”
非常好,我们将之前关于偏导数链式法则中不能“约掉”偏导符号的问题,统一使用 二重复合函数: z f ( u ( x , y ) , v ( x , y ) ) \boxed{z f(u(x,y),\ v(x,y))} zf(u(x,y), v(x,y)) 来全面说明。我们会展示其全微分形式(偏导…...
