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

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 表达式是一种匿名函数&#xff0c;最早在 C11 引入&#xff0c;用于简化函数对象的…...

《多线程基础之条件变量》

【条件变量导读】条件变量是多线程中比较灵活而且容易出错的线程同步手段&#xff0c;比如&#xff1a;虚假唤醒、为啥条件变量要和互斥锁结合使用&#xff1f;windows和linux双平台下&#xff0c;初始化、等待条件变量的api一样吗&#xff1f; 本文将分别为您介绍条件变量在w…...

21款炫酷烟花合集

系列专栏 《Python趣味编程》《C/C趣味编程》《HTML趣味编程》《Java趣味编程》 写在前面 Python、C/C、HTML、Java等4种语言实现18款炫酷烟花的代码。 Python Python烟花① 完整代码&#xff1a;Python动漫烟花&#xff08;完整代码&#xff09; ​ Python烟花② 完整…...

智能风控 数据分析 groupby、apply、reset_index组合拳

目录 groupby——分组 本例 apply——对每个分组应用一个函数 等价用法 reset_index——重置索引 使用前​编辑 注意事项 groupby必须配合聚合函数、 关于agglist 一些groupby试验 1. groupby对象之后。sum&#xff08;一个列名&#xff09; 2. groupby对象…...

Python网络自动化运维---用户交互模块

文章目录 目录 文章目录 前言 实验环境准备 一.input函数 代码分段解析 二.getpass模块 前言 在前面的SSH模块章节中&#xff0c;我们都是将提供SSH服务的设备的账户/密码直接写入到python代码中&#xff0c;这样很容易导致账户/密码泄露&#xff0c;而使用Python中的用户交…...

【JVM】调优

目的&#xff1a; 减少minor gc、full gc的次数&#xff0c;也就是减少STW的时间&#xff0c;因为java虚拟机在做后台垃圾收集线程的时候&#xff0c;会停掉其他线程&#xff0c;专门做垃圾收集&#xff0c;这样会影响网站的性能&#xff0c;以及用户的体验。 调优位置&#x…...

软件测试 —— jmeter(2)

软件测试 —— jmeter&#xff08;2&#xff09; HTTP默认请求头&#xff08;元件&#xff09;元件作用域和取样器作用域HTTP Cookie管理器同步定时器jmeter插件梯度压测线程组&#xff08;Stepping Thread Group&#xff09;参数解析总结 Response Times over TimeActive Thre…...

为什么LabVIEW适合软硬件结合的项目?

LabVIEW是一种基于图形化编程的开发平台&#xff0c;广泛应用于软硬件结合的项目中。其强大的硬件接口支持、实时数据采集能力、并行处理能力和直观的用户界面&#xff0c;使得它成为工业控制、仪器仪表、自动化测试等领域中软硬件系统集成的理想选择。LabVIEW的设计哲学强调模…...

【机器学习】自定义数据集 使用tensorflow框架实现逻辑回归并保存模型,然后保存模型后再加载模型进行预测

一、使用tensorflow框架实现逻辑回归 1. 数据部分&#xff1a; 首先自定义了一个简单的数据集&#xff0c;特征 X 是 100 个随机样本&#xff0c;每个样本一个特征&#xff0c;目标值 y 基于线性关系并添加了噪声。tensorflow框架不需要numpy 数组转换为相应的张量&#xff0…...

.NET Core缓存

目录 缓存的概念 客户端响应缓存 cache-control 服务器端响应缓存 内存缓存&#xff08;In-memory cache&#xff09; 用法 GetOrCreateAsync 缓存过期时间策略 缓存的过期时间 解决方法&#xff1a; 两种过期时间策略&#xff1a; 绝对过期时间 滑动过期时间 两…...

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 不再是通过密码登录了&#xff0c;需要本地生成一个密钥&#xff0c;配置到gihub中才能使用 2 步骤 &#xff08;1&#xff09;首先配置用户名和邮箱 git config --global user.name "用户名"git config --global…...

《企业应用架构模式》笔记

领域逻辑 表模块和数据集一起工作-> 先查询出一个记录集&#xff0c;再根据数据集生成一个&#xff08;如合同&#xff09;对象&#xff0c;然后调用合同对象的方法。 这看起来很想service查询出一个对象&#xff0c;但调用的是对象的方法&#xff0c;这看起来像是充血模型…...

深入理解 C 语言函数指针的高级用法:(void (*) (void *)) _IO_funlockfile

深入理解 C 语言函数指针的高级用法 函数指针是 C 语言中极具威力的特性&#xff0c;广泛用于实现回调、动态函数调用以及灵活的程序设计。然而&#xff0c;复杂的函数指针声明常常让即使是有经验的开发者也感到困惑。本文将从函数指针的基本概念出发&#xff0c;逐步解析复杂…...

【JavaSE】图书管理系统

前言&#xff1a;为了巩固之前学习的java知识点&#xff0c;我们用之前学习的java知识点&#xff08;方法&#xff0c;数组&#xff0c;类和对象&#xff0c;封装&#xff0c;继承&#xff0c;多态&#xff0c;抽象类&#xff0c;接口&#xff09;来实现一个简单的图书管理系统…...

【C++数论】880. 索引处的解码字符串|2010

本文涉及知识点 数论&#xff1a;质数、最大公约数、菲蜀定理 LeetCode880. 索引处的解码字符串 给定一个编码字符串 s 。请你找出 解码字符串 并将其写入磁带。解码时&#xff0c;从编码字符串中 每次读取一个字符 &#xff0c;并采取以下步骤&#xff1a; 如果所读的字符是…...

C++/stack_queue

目录 1.stack 1.1stack的介绍 1.2stack的使用 练习题&#xff1a; 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进行绘图&#xff0c;效果如下&#xff1a; 业务实现 代码框架 代码框架如下&#xff1a; . 依赖包下载 我们通过网站下载自己需要的涉及的图标&#xff0c;勾选之后进…...

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是啥&#xff0c;能干嘛 我们经常会用es来实现一些关于检索&#xff0c;关于分析的业务。但是es本身并没有UI,我们只能通过调用api来完成一些能力。而kibana就是他的一个外置UI&#xff0c;你完全可以这么理解。 当我们进入kibana的主页的时候你可以看到这样的布局。…...

uniapp 对接腾讯云IM群组成员管理(增删改查)

UniApp 实战&#xff1a;腾讯云IM群组成员管理&#xff08;增删改查&#xff09; 一、前言 在社交类App开发中&#xff0c;群组成员管理是核心功能之一。本文将基于UniApp框架&#xff0c;结合腾讯云IM SDK&#xff0c;详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

Linux简单的操作

ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

腾讯云V3签名

想要接入腾讯云的Api&#xff0c;必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口&#xff0c;但总是卡在签名这一步&#xff0c;最后放弃选择SDK&#xff0c;这次终于自己代码实现。 可能腾讯云翻新了接口文档&#xff0c;现在阅读起来&#xff0c;清晰了很多&…...

Qt 事件处理中 return 的深入解析

Qt 事件处理中 return 的深入解析 在 Qt 事件处理中&#xff0c;return 语句的使用是另一个关键概念&#xff0c;它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别&#xff1a;不同层级的事件处理 方…...

阿里云Ubuntu 22.04 64位搭建Flask流程(亲测)

cd /home 进入home盘 安装虚拟环境&#xff1a; 1、安装virtualenv pip install virtualenv 2.创建新的虚拟环境&#xff1a; virtualenv myenv 3、激活虚拟环境&#xff08;激活环境可以在当前环境下安装包&#xff09; source myenv/bin/activate 此时&#xff0c;终端…...

LangChain 中的文档加载器(Loader)与文本切分器(Splitter)详解《二》

&#x1f9e0; LangChain 中 TextSplitter 的使用详解&#xff1a;从基础到进阶&#xff08;附代码&#xff09; 一、前言 在处理大规模文本数据时&#xff0c;特别是在构建知识库或进行大模型训练与推理时&#xff0c;文本切分&#xff08;Text Splitting&#xff09; 是一个…...

用神经网络读懂你的“心情”:揭秘情绪识别系统背后的AI魔法

用神经网络读懂你的“心情”:揭秘情绪识别系统背后的AI魔法 大家好,我是Echo_Wish。最近刷短视频、看直播,有没有发现,越来越多的应用都开始“懂你”了——它们能感知你的情绪,推荐更合适的内容,甚至帮客服识别用户情绪,提升服务体验。这背后,神经网络在悄悄发力,撑起…...

【记录坑点问题】IDEA运行:maven-resources-production:XX: OOM: Java heap space

问题&#xff1a;IDEA出现maven-resources-production:operation-service: java.lang.OutOfMemoryError: Java heap space 解决方案&#xff1a;将编译的堆内存增加一点 位置&#xff1a;设置setting-》构建菜单build-》编译器Complier...

【汇编逆向系列】六、函数调用包含多个参数之多个整型-参数压栈顺序,rcx,rdx,r8,r9寄存器

从本章节开始&#xff0c;进入到函数有多个参数的情况&#xff0c;前面几个章节中介绍了整型和浮点型使用了不同的寄存器在进行函数传参&#xff0c;ECX是整型的第一个参数的寄存器&#xff0c;那么多个参数的情况下函数如何传参&#xff0c;下面展开介绍参数为整型时候的几种情…...

【向量库】Weaviate概述与架构解析

文章目录 一、什么是weaviate二、High-Level Architecture1. Core Components2. Storage Layer3. 组件交互流程 三、核心组件1. API Layer2. Schema Management3. Vector Indexing3.1. 查询原理3.2. 左侧&#xff1a;Search Process&#xff08;搜索流程&#xff09;3.3. 右侧&…...