深入理解 C++11 Lambda 表达式及其捕获列表

随着 C++11 的引入,Lambda 表达式成为了一种非常有用的功能。它允许在代码中定义匿名函数,并可以直接在函数体中使用外部变量。这一特性不仅增强了代码的简洁性和灵活性,尤其是在处理回调、事件或多线程编程时显得格外强大。在 Qt 中,Lambda 表达式广泛应用于信号和槽机制,使得处理异步操作时更加简便。

本文将详细介绍 C++11 Lambda 表达式的捕获列表及其应用。


什么是 Lambda 表达式?

Lambda 表达式是定义在局部作用域中的匿名函数,它的语法结构如下:

 

[capture](parameters) -> return_type { body_of_lambda }

  • [capture]:捕获列表,用来定义 Lambda 表达式能够使用哪些外部作用域中的变量。
  • (parameters):参数列表,类似于普通函数的参数。
  • -> return_type(可选):指定返回类型。如果不写,编译器会自动推断返回类型。
  • { body_of_lambda }:Lambda 函数体,包含需要执行的代码。

其中,捕获列表是 Lambda 表达式的核心,它定义了 Lambda 内部如何访问外部的变量。捕获列表决定了 Lambda 是否可以修改外部的变量,以及是通过值还是引用捕获外部变量。


Lambda 表达式的捕获列表详解

捕获列表允许 Lambda 表达式捕获外部作用域中的变量,并决定如何捕获这些变量。以下是几种常见的捕获方式:

1. [&]:捕获所有外部变量,并以引用的方式使用

使用 [&],Lambda 表达式将捕获外部作用域中的所有变量,并且以引用的方式使用。这意味着 Lambda 表达式可以修改外部变量的值。

示例:
#include <iostream>int main() {int a = 10;int b = 20;auto lambda = [&]() {a += 5;b += 5;};lambda();  // 修改 a 和 bstd::cout << "a = " << a << ", b = " << b << std::endl;  // 输出: a = 15, b = 25return 0;
}
解释:
  • 这里的 [&] 表示捕获所有外部变量的引用,Lambda 内部可以修改 ab
  • 调用 lambda() 后,外部的 ab 被修改。
2. [=]:捕获所有外部变量,并以值的方式使用

使用 [=],Lambda 表达式将捕获外部所有变量的副本,即 Lambda 内部只能读取外部变量的值,但无法修改它们。

示例:
#include <iostream>int main() {int a = 10;int b = 20;auto lambda = [=]() {std::cout << "Inside Lambda: a = " << a << ", b = " << b << std::endl;// a += 5; // 错误: 不能修改值捕获的变量};a = 100;  // 修改外部变量 alambda();  // 输出仍然是 a = 10, b = 20return 0;
}
解释:
  • [=] 捕获 ab 的值,因此 Lambda 内部只能访问这些变量的拷贝。
  • 即使外部修改了 a 的值,Lambda 内部的 a 仍然保持最初的值(10)。
3. [this]:捕获当前类的 this 指针

使用 [this] 捕获当前类的 this 指针,允许 Lambda 表达式访问当前类的成员变量和成员函数。这在 Qt 的信号槽机制中非常常见。

示例:
#include <iostream>class MyClass {
public:MyClass(int value) : value(value) {}void show() {auto lambda = [this]() {std::cout << "Value inside lambda: " << value << std::endl;};lambda();}private:int value;
};int main() {MyClass obj(42);obj.show();  // 输出: Value inside lambda: 42return 0;
}
解释:
  • 使用 [this],Lambda 可以访问类的成员变量 value
  • lambda() 被调用时,Lambda 可以直接读取和操作 this 指针指向的对象的成员。
4. [var]:捕获指定的变量 var,以值的方式使用

如果你只想捕获特定的变量而不是所有外部变量,可以使用 [var] 捕获指定的变量,并且以值的方式捕获。

示例:
#include <iostream>int main() {int x = 10;int y = 20;auto lambda = [x]() {std::cout << "x = " << x << std::endl;// x += 5; // 错误:不能修改 x 的值,因为它是值捕获的};lambda();return 0;
}
解释:
  • [x] 表示只捕获变量 x 的值,Lambda 内部不能修改它。
  • y 没有被捕获,因此 Lambda 无法访问 y
5. [&var]:捕获指定的变量 var,以引用的方式使用

[var] 类似,[&var] 捕获指定的变量,但通过引用捕获,允许 Lambda 修改该变量。

示例:
#include <iostream>int main() {int x = 10;int y = 20;auto lambda = [&x]() {x += 5;std::cout << "x = " << x << std::endl;};lambda();  // x 被修改为 15std::cout << "x outside lambda: " << x << std::endl;  // 输出: x = 15return 0;
}
解释:
  • [&x] 捕获变量 x 的引用,因此 Lambda 可以修改外部的 x
  • lambda() 调用后,x 从 10 变为 15。
6. [&, var]:捕获所有外部变量,以引用方式捕获 var

使用 [&, var] 可以混合捕获方式,捕获所有变量的引用,同时捕获某些变量的值。这样可以灵活控制不同变量的捕获方式。

示例:
#include <iostream>int main() {int x = 10;int y = 20;auto lambda = [&, y]() {x += 5;std::cout << "x = " << x << ", y = " << y << std::endl;};lambda();  // x 被修改为 15, y 保持不变return 0;
}
解释:
  • [&, y] 表示捕获 x 的引用,但捕获 y 的值。
  • Lambda 内部可以修改 x,但 y 保持不变。

捕获列表的使用限制

  1. 生命周期问题:捕获的变量必须在 Lambda 执行期间保持有效。如果捕获的是局部变量,而 Lambda 在局部变量已经被销毁后执行,就会导致未定义行为。
  2. this 指针的捕获:如果使用 [this] 捕获当前对象的 this 指针,要确保 this 指针在 Lambda 执行时是有效的。否则,可能会访问无效的内存。
  3. 修改权限:如果捕获变量是以值的方式进行的,Lambda 无法修改这些变量。如果需要修改,应该使用引用捕获。

Lambda 表达式的应用场景

  1. 信号槽机制:在 Qt 的信号槽机制中,Lambda 表达式极大简化了槽函数的编写,无需单独定义槽函数,而是可以将处理逻辑直接嵌入到 connect() 调用中。
  2. 回调函数:Lambda 适合用作回调函数,特别是当你只需要定义一次性函数时,Lambda 提供了更加简洁的方式。
  3. 多线程编程:在 C++11 的多线程库中,Lambda 表达式可以方便地传递给线程执行的任务。
  4. 简化代码:使用 Lambda 可以减少代码中小函数的定义,提升代码的可读性。

总结

C++11 中的 Lambda 表达式通过捕获列表提供了灵活的方式来访问外部变量。根据需求,你可以选择值捕获或引用捕获,也可以结合使用不同的捕获方式。Lambda 表达式大大简化了代码编写,尤其是在需要回调、异步任务或信号槽等场景中,Lambda 提供了更高的灵活性和简洁性。

  • [&] 捕获所有外部变量的引用,允许修改外部变量。
  • [=] 捕获所有外部变量的副本,只允许读取,不允许修改。
  • [this] 捕获类的 this 指针,方便访问类的成员变量和成员函数。
  • [var] 捕获指定变量的副本,允许读取但不允许修改。
  • [&var] 捕获指定变量的引用,允许修改该变量。

通过对捕获列表的理解和灵活运用,Lambda 表达式可以帮助你编写更简洁、灵活的代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1551438.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

golang 获取证书的生效及过期时间

测试样例 func TestGetCertVaildTime(t *testing.T) {certPEM, err : ioutil.ReadFile("aa.bbb.com.crt")if err ! nil {fmt.Println("读取证书文件出错:", err)return}// 解码PEM格式的证书block, _ : pem.Decode(certPEM)if block nil {fmt.Println(&q…

智源研究院推出全球首个中文大模型辩论平台FlagEval Debate

近日&#xff0c;智源研究院推出全球首个中文大模型辩论平台FlagEval Debate&#xff0c;旨在通过引入模型辩论这一竞争机制对大语言模型能力评估提供新的度量标尺。该平台是智源模型对战评测服务FlagEval大模型角斗场的延展&#xff0c;将有助于甄别大语言模型的能力差异。 F…

vector中push_back和emplace_back的区别

push_back 在引入右值引用&#xff0c;转移构造函数&#xff0c;转移复制运算符之前&#xff0c;通常使用push_back()向容器中加入一个右值元素&#xff08;临时对象&#xff09;的时候&#xff0c;首先会调用构造函数构造这个临时对象&#xff0c;然后需要调用拷贝构造函数将…

Redis入门第一步:认识Redis与快速安装配置

认识Redis与快速安装配置&#x1f343; Redis是什么&#x1f432; 1.Redis的背景&#x1f38d; Redis&#xff08;Remote Dictionary Server&#xff09;译为"远程字典服务"&#xff0c;它是一款基于内存实现的键值型 NoSQL 数据库&#xff0c; 通常也被称为数据结…

pytorch线性/非线性回归拟合

一、线性回归 1. 导入依赖库 import numpy as np import matplotlib.pyplot as plt import torch from torch import nn, optim from torch.autograd import Variable numpy&#xff1a;用来构建数据matplotlib.pyplot&#xff1a; 将构建好的数据可视化torch.nn&#xff1a…

2024还在拼多多赚钱的,无不满足这几个条件

拼多多只是我棋盘上的一小步&#xff0c;整个棋局几人看懂了&#xff1f; 如果我说我做拼多多&#xff0c;其实是另有目的&#xff0c;拼多多只是我棋局里的一小步&#xff0c;你们信吗&#xff1f;认真看文章&#xff0c;后面会为大家揭秘&#xff01; 先来客观公正的回答下…

Queued Synchronous Peripheral Interface (QSPI)

文章目录 1. 介绍2. Feature List3. 概述3.1 QSPI框图3.2 操作模式3.3 三线模式3.4 时钟极性和时钟相位 4. Master模式4.1 状态机4.2 采样点4.3 波特率4.4 通信模式4.4.1 短数据模式4.4.2 长数据模式4.4.3 短连续模式4.4.4 长连续模式4.4.5 单配置多帧模式4.4.6 XXL模式4.4.7 M…

选择国企eHR人事管理系统的时候,应该注意什么?

近年来&#xff0c;中国正步入高速发展的黄金时期&#xff0c;国有企业&#xff08;国企&#xff09;在追求效率和管理水平提升方面迈出了重要步伐。为了进一步实现数字化、流程化和科学化管理&#xff0c;越来越多的国企选择引进eHR&#xff08;电子人力资源管理&#xff09;系…

【Diffusion分割】MedSegDiff-v2:Diffusion模型进行医学图像分割

MedSegDiff-V2: Diffusion-Based Medical Image Segmentation with Transformer 摘要&#xff1a; 最近的研究揭示了 DPM 在医学图像分析领域的实用性&#xff0c;医学图像分割模型在各种任务中表现出的出色性能就证明了这一点。尽管这些模型最初是以 UNet 架构为基础的&…

opencv实战项目(三十):使用傅里叶变换进行图像边缘检测

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一&#xff0c;什么是傅立叶变换&#xff1f;二&#xff0c;图像处理中的傅立叶变换&#xff1a;三&#xff0c;傅里叶变换进行边缘检测&#xff1a; 一&#xff0c…

13个大V出文需要准确把握的重要因素

推文作为全球最大的社交平台之一&#xff0c;吸引了很多大V&#xff08;即具有巨大粉丝团的影响力和的账户&#xff09;的关注。那些大V常常运用推文发布相关各种各样热点的营销推广信息&#xff0c;以吸引更多人的关注参与。推文的发布时间段是V在宣传推广过程中需要准确把握的…

【真实访问】那些选择土木专业的学生,后来怎么样了?

“你会让孩子报土木专业吗&#xff1f;” 7月15日&#xff0c;澎湃新闻在微博上发起线上调研&#xff0c;截至16日12时&#xff0c;8000多人参与了投票&#xff0c;结果显示近7000人选择“不会&#xff0c;天坑专业”。短短几年时间&#xff0c;土木工程专业的报考从“香饽饽”…

CAN总线的错误类型

前言 CAN总线的错误类型主要包括&#xff1a;位错误、填充错误、格式错误、ACK错误和CRC错误。这里一定要做好CAN总线的错误类型、错误帧类型、节点状态之间的区别。 错误类型是帧传输出错的原因类型&#xff1b;错误帧类型&#xff08;主动错误帧、被动错误帧&#xff09;是帧…

基于IntraWeb的数据表格的多选实现

基于IntraWeb的数据表格的多选实现 既可以单条操作&#xff0c;也可以多选操作。 delphi源代码。 BS开发Web网站开发&#xff0c;不需要安装服务器&#xff0c;Apache和IIS都不需要&#xff0c;自带企业级服务器。 运行exe服务器就架好了&#xff0c;直接打开手机浏览器或者…

Zombie Slaughter 写实30个僵尸丧尸带动画角色模型

包含30个操纵的僵尸(15个男性和15个女性角色)+动画 所有僵尸都有分离的身体部位,以获得更好的射击/砍杀体验:) PBR材质包含4种纹理(基色、法线、粗糙度、AO),分辨率为4096x4096。 动画包括: -闲置 -步行 - 走回去 - 向右转 - 向左转 -担心 -尖叫 - 走路惹 -快跑 -阿格罗…

人工智能与伦理:如何确保AI应用中的隐私保护

引言 随着人工智能技术的飞速发展&#xff0c;AI已经渗透到我们生活的各个领域&#xff0c;从智能助手到个性化推荐系统&#xff0c;再到医疗诊断和金融服务&#xff0c;人工智能正在为我们带来前所未有的便利。然而&#xff0c;伴随着AI的广泛应用&#xff0c;隐私保护问题日益…

优选驾考系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;驾校管理&#xff0c;驾考文章管理&#xff0c;驾照类型管理&#xff0c;报名入口管理&#xff0c;学员报名管理&#xff0c;练车预约管理&#xff0c;考试场地管理 微信端账号功能包括&#xff1a;系统…

加油卡APP系统:省时、优惠、安心!

在汽车加油的刚需下&#xff0c;如何更加优惠的“加油”成为了大众关心的重点&#xff0c;而以优惠为主的加油卡系统也成为了大众的主要选择。 加油卡系统是汽车加油线上的服务系统&#xff0c;拥有全国各地的加油站权限&#xff0c;能够让车主在手机上进行充值&#xff0c;同…

VMware虚拟机连接公网,和WindTerm

一、项目名称 vmware虚拟机连接公网和windterm 二、项目背景 需求1&#xff1a;windows物理机&#xff0c;安装了vmware虚拟机&#xff0c;需要访问公网资源&#xff0c;比如云服务商的yum仓库&#xff0c;国内镜像加速站的容器镜像&#xff0c;http/https资源。 需求2&#xf…

【git】git分支之谜-十分钟给你讲透彻

这里写自定义目录标题 引子分支的直观模型在 git 中&#xff0c;分支是完整的提交记录分支用commit ID存储人们的直觉通常并没有那么错rebase 使用“直观”的分支概念merge也使用“直观”的分支概念github pull request 也使用直观的想法直觉很好&#xff0c;但它也有一些局限性…