c++中 Lambda表达式

 Lambda优化技巧

  • 尽量使用值捕获简单类型

  • 避免捕获大型对象(使用引用或智能指针)

  • 将不修改的捕获标记为const

  • 使用初始化捕获移动语义资源


前言

1. Lambda表达式基本语法

[捕获列表](参数列表) mutable(可选) 异常属性(可选) -> 返回类型(可选) {// 函数体
}

捕获列表决定了lambda表达式可以访问哪些外部变量以及如何访问它们:

  • []:不捕获任何外部变量     [=]:以值捕获所有外部变量   

  • [&]:以引用捕获所有外部变量     [var]:以值捕获特定变量var

  • [&var]:以引用捕获特定变量var     [=, &var]:默认以值捕获,但var以引用捕获

  • [&, var]:默认以引用捕获,但var以值捕获     [this]:捕获当前类的this指针

int a = 1, b = 2, c = 3;auto lambda1 = [=]() { return a + b; };  // 值捕获a和b
auto lambda2 = [&]() { c = a + b; };     // 引用捕获a、b、c
auto lambda3 = [a, &b]() { b = a + 10; }; // 值捕获a,引用捕获b

返回类型推断

当lambda体只有一条return语句时,返回类型可以自动推断:

auto lambda = [](int x) { return x * x; };  // 返回类型推断为int

复杂情况下需要显式指定返回类型:

auto lambda = [](int x) -> double {if (x > 0) return 1.0 / x;else return x * x;
};

通用Lambda (C++14)

C++14引入了通用lambda,可以使用auto参数:

auto print = [](auto x) { cout << x << endl; };
print(123);    // 输出123
print("hello"); // 输出hello
 可变Lambda (mutable)
int counter = 0;// 没有mutable会编译错误
auto incrementer = [counter]() mutable {return ++counter; // 修改的是副本
};incrementer(); // 1
incrementer(); // 2
cout << counter; // 仍然是0

编译错误:默认 lambda 的 operator() 是 const 的,不能修改按值捕获的变量。修复方式:加 mutable 或改用引用捕获 [&counter]

该 lambda 会被转换为类似以下的类:

class __Lambda_Counter {
public:__Lambda_Counter(int counter) : counter(counter) {}  // 拷贝构造// mutable 移除了 operator() 的 const 限定int operator()() {return ++counter;  // 允许修改成员变量}private:int counter;  // 按值捕获的副本
};__Lambda_Counter incrementer(counter);  // 创建闭包对象

2. Lambda表达式的完整生命周期

Lambda表达式实际上是一个编译器生成的匿名类实例,理解这一点对掌握Lambda至关重要

int x = 10;
auto lambda = [x](int y) mutable {x += y;return x;
};// 编译器生成的等价类
class __Lambda_10 {
public:__Lambda_10(int x) : x(x) {}int operator()(int y) {x += y;return x;}private:int x;
};__Lambda_10 lambda(5);

mutable 的作用

  1. 默认情况下,lambda 的 operator() 是 const 的,不能修改捕获的变量加上 mutable 后,operator() 变为非 const,允许修改按值捕获的变量(但不会影响外部的原始变量)。
  2. 捕获方式:如果改成 [&x],则捕获引用,修改会影响外部的 x[x] 是按值捕获,lambda 内部存储的是 x 的副本。调用方式lambda(5) 实际上是用 lambda.operator()(5),就像调用普通函数一样。

2. 捕获方式的深层细节

(1) 值捕获的陷阱
vector<int> data{1, 2, 3};// 看似捕获了data,实则捕获的是data的拷贝
auto lambda = [data]() {// 这里操作的是data的副本for(auto& x : data) x *= 2;
};// 原始data未被修改
lambda();
for(auto x : data) cout << x << " "; // 输出: 1 2 3

​​​​​​​按值捕获 [data]:Lambda 内部会生成一个 data 的完整拷贝(调用 vector 的拷贝构造函数)。修改的是副本x *= 2 操作的是 lambda 内部的副本,不影响外部的 data

你的 lambda 会被编译器转换为类似下面的类:

class __Lambda_Data {
public:__Lambda_Data(const vector<int>& data) : data(data) {} // 拷贝构造void operator()() {for(auto& x : data) x *= 2; // 修改的是成员变量 data}private:vector<int> data; // 按值捕获的副本
};__Lambda_Data lambda(data); // 调用时拷贝 data
lambda();                  // 修改的是内部的 data

这样的就使按值捕获都会在lambda类里面拷贝一份副样本这样的话会导致里面实现的函数所得到的值不会改变原来的参数只会改变你拷贝构造的那一份数据

如果需要修改外部 data,需使用 引用捕获 [&data]

(2) 引用捕获的生命周期风险
auto createLambda() {int local = 42;return [&local]() { return local; }; // 危险!返回后local被销毁
}auto badLambda = createLambda();
cout << badLambda(); // 未定义行为,可能崩溃或输出垃圾值

​​​​​​​local 的生命周期:仅在 createLambda() 函数执行期间有效Lambda 行为:捕获了 local 的引用,但该引用在函数返回后失效。

(3) 初始化捕获 (C++14)
auto ptr = make_unique<int>(10);// C++14引入的初始化捕获
auto lambda = [p = move(ptr)]() {return *p;
};// ptr已被转移所有权,现在为nullptr

4. 模板Lambda (C++20)

C++20引入了模板参数支持:

auto genericLambda = []<typename T>(T x, T y) {return x + y;
};cout << genericLambda(1, 2);      // 3
cout << genericLambda(1.5, 2.5);  // 4.0

这样的话就方便函数的打印可以用来直接打印函数

std::vector<int> vi{1, 2, 3};
std::vector<double> vd{1.1, 2.2};
auto print = []<typename T>(const std::vector<T>& v) {for (const auto& x : v) std::cout << x << " ";
};
print(vi);  // 1 2 3
print(vd);  // 1.1 2.2

 常见Lambda错误

  • 悬空引用:Lambda生命周期长于捕获的引用

  • 意外拷贝:捕获大型对象未使用引用

  • mutable遗漏:需要修改值捕获变量时

  • 类型不匹配:返回类型推断错误


总结

  1. 默认选择Lambda:除非需要参数重排/部分绑定(此时用bind)

  2. 显式优于隐式:避免[=]/[&]全捕获,明确列出所需变量

  3. 复杂度控制:超过5行的逻辑考虑提取为命名函数

  4. 线程安全:多线程共享Lambda时避免可变共享状态

  5. 结合现代特性:与auto/constexpr/concept等特性协同使用

Lambda表达式重新定义了C++的函数式编程范式,合理运用可使代码既保持高性能又提升可读性,是现代C++开发的核心技能之一。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

睿是信息携手Arctera,深化服务中国市场,共筑数据管理新未来

2025年6月23日&#xff0c;为了更加深入服务中国大陆地区的广大用户&#xff0c;上海睿是信息科技有限公司&#xff08;以下简称“睿是信息”&#xff09;与全球数据管理领域的领导者Arctera&#xff0c;双方正式达成战略合作&#xff0c;自2025年7月7日起&#xff0c;睿是信息…

【WebGIS系列】WebGIS 开发相关的资源

目录 数据 GIS 软件 地图渲染库 EPSG 相关工具 资源 以下为个人收集的与 WebGIS 开发相关的资源&#xff08;排名不分前后&#xff09;&#xff0c;欢迎补充。 数据 天地图(opens in a new tab)国家统计局行政区划(opens in a new tab)民政部全国行政区划信息查询平台(…

【单调栈】-----【小A的柱状图】

小A的柱状图 题目链接 题目描述 柱状图是有一些宽度相等的矩形下端对齐以后横向排列的图形&#xff0c;但是小A的柱状图却不是一个规范的柱状图&#xff0c;它的每个矩形下端的宽度可以是不相同的一些整数&#xff0c;分别为 a [ i ] a[i] a[i]&#xff0c;每个矩形的高度是…

MySQL 索引优化与慢查询优化:原理与实践

MySQL是一个广泛使用的关系型数据库管理系统&#xff0c;优化MySQL的性能对于保证应用的高效运行至关重要。本文将详细介绍MySQL索引优化与慢查询优化的原理和实践方法。 一、MySQL索引优化 1.1 索引的基本概念 索引是一种用于提高数据库查询速度的数据结构。常见的索引类型…

【AS32系列MCU调试教程】应用开发:基于AS32芯片的流水灯功能实现

摘要&#xff1a; 本文以国科安芯的AS32系列MCU芯片为例&#xff0c;聚焦于基于 AS32 芯片的流水灯功能开发&#xff0c;深入阐述了开发环境搭建、工程配置以及调试等关键环节。通过详尽的实验过程与结果分析&#xff0c;旨在为相关领域技术人员提供一套系统、高效且成本可控的…

爬虫001----介绍以及可能需要使用的技术栈

首先1️⃣。。。全篇使用的技术栈当然是python了&#xff0c;毕竟作为一名点点点工程师&#xff0c;实际工作中做测试开发用的也是python&#xff0c;毕竟测试框架么&#xff0c;不需要什么"速度"。也会一点点cpp和js&#xff0c;但不多。什么&#xff1f;你说go和ja…

Java 中基于条件动态决定字段参与分组的实现方法

在 Java 的 Stream API 中&#xff0c;Collectors.groupingBy()方法为数据分组提供了强大的支持。通过它&#xff0c;我们可以轻松地将集合中的元素按照某个属性进行分组&#xff0c;比如按照商品类别、日期等。然而&#xff0c;在实际业务场景中&#xff0c;有时需要根据特定条…

AppBarLayout+ CoordinatorLayout,ViewPager2为什么不会覆盖AppBarLayout

<?xml version"1.0" encoding"utf-8"?> <layout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:app"http://schemas.android.com/apk/res-auto"xmlns:tools"http://schemas.android.com/tools&quo…

【群体智能优化算法系列 】一 粒子群算法 (Particle Swarm Optimization, PSO)

【群体智能优化算法系列 】一 粒子算法 一&#xff1a;前言二&#xff1a;算法原理2.1 核心思想2.2 PSO核心公式​2.3 PSO算法流程图 三&#xff1a;python实现 二维Rastrigin函数 最低点检索例子参考 一&#xff1a;前言 粒子群算法是由Kennedy和Eberhart在1995年提出的一种基…

Jupyter notebook调试:设置断点运行

写了一段小代码&#xff0c;主要是用来测试一段序列的k均值聚类效果&#xff1b; 中间想到debug一下&#xff0c;但是想到自己似乎从来没有正式地接触过jupyter notebook中地debug&#xff0c;平时也只是多开几个cell&#xff0c;然后在其他cell中复制粘贴部分代码&#xff0c…

[12-2] BKP备份寄存器RTC实时时钟 江协科技学习笔记(14个知识点)

1 2 3 4 5 6 7 8 RTC是“Real-Time Clock”的缩写&#xff0c;中文意思是“实时时钟”。这是一种在电子设备中使用的时钟&#xff0c;它能够提供准确的时间信息&#xff0c;即使在设备断电的情况下也能继续运行&#xff0c;因为它通常由一个小型电池供电。RTC广泛应用于计算机…

优化给AI的“提问技巧”(提示工程),让大型语言模型(比如GPT)更好地扮演“心理治疗助手”的角色

优化给AI的“提问技巧”(提示工程),让大型语言模型(比如GPT)更好地扮演“心理治疗助手”的角色 尤其是在“问题解决疗法”(PST)中帮助 caregivers(家庭护理者)缓解焦虑、疲劳等心理症状。以下是核心内容的通俗解读: 一、研究背景:AI当心理医生靠谱吗? 现状:全球…

Java的lambda表达式应用

Lambda表达式是Java 8引入的一项强大特性&#xff0c;它允许以更加简洁的方式表示匿名函数。Lambda表达式不仅让代码更加简洁、清晰&#xff0c;而且为函数式编程提供了有力支持&#xff0c;从而提升了Java语言的表达能力。 本文主要讲解lambda应用stream处理集合的应用。 1、…

云原生/容器相关概念记录

文章目录 网络与虚拟化技术云平台与架构容器与编排容器网络方案性能优化与工具硬件与协议 网络与虚拟化技术 P4可编程网关 P4: Programming Protocol-independent Packet Processors一种基于P4语言的可编程网络设备&#xff0c;支持自定义数据包处理逻辑。P4可编程技术详解&am…

[C++] traits机制

文章目录 C之type_traitsis_floating_point<T> ..的使用std::enable_if<T>::type的使用std::remove_cv 如何自定义traits C之type_traits is_floating_point …的使用 一般在定义打印模板函数的时候&#xff0c;当我们用printf进行终端日志打印&#xff0c;需要根…

OpenCV 视频处理与保存

一、知识点 1、VideoCapture类 (1)、用于从视频文件、摄像机或图像序列中捕获视频帧。 (2)、构造函数 VideoCapture(const String & filename, int apiPreference CAP_ANY) a、filename可以是视频文件的名称(例如"video.avi")&#xff0c;可以是图…

【Leetcode】字符串之二进制求和、字符串相乘

文章目录 算法原理二进制求和题目链接题目描述解题思路代码 字符串相乘题目链接题目描述解题思路代码 算法原理 这两道题都是属于算法里一种经典题型&#xff1a;高精度加/减/乘/除法&#xff0c;需要我们模拟加/减/乘/除 列竖式运算。 二进制求和 题目链接 题目链接 题目描…

MongoDB:索引

目录 1、索引数据结构&#xff1a;B-树 2、索引类型 2.1 单字段索引 2.2 复合索引&#xff08;最重要&#xff01;&#xff09; 2.3 多键索引&#xff08;数组字段&#xff09; 2.4 地理空间索引 2.5 全文索引 2.6 哈希索引&#xff08;分片专用&#xff09; 2.7 TTL …

【大模型】Transformer架构完全解读:从“盲人摸象“到“通晓万物“的AI进化论

&#x1f916; Transformer架构完全解读&#xff1a;从"盲人摸象"到"通晓万物"的AI进化论 —— 一位大模型探索者的技术日记 ☕ 第一章&#xff1a;为什么说Transformer是AI界的"蒸汽机革命"&#xff1f; 1.1 从RNN到Transformer&#xff1a;…

JavaEE:使用JMeter进行接口并发测试

一、下载与安装&#xff1a; 1.下载apache-jmeter-5.6.3.zip&#xff1a; https://jmeter.apache.org/download_jmeter.cgi 2.解压到D:\Program Files\apache-jmeter-5.6.3目录 3.添加JDK环境配置到D:\Program Files\apache-jmeter-5.6.3\bin\jmeter.bat文件开头&#xff1…