0

0

c++怎么使用lambda值捕获与引用捕获_c++ 匿名函数变量作用域【指南】

冰火之心

冰火之心

发布时间:2025-12-26 12:07:50

|

552人浏览过

|

来源于php中文网

原创

值捕获[=]复制变量,修改副本不影响外部原始值;基本类型安全但不可反向写回,大对象可能深拷贝;需修改副本须加mutable关键字。

c++怎么使用lambda值捕获与引用捕获_c++ 匿名函数变量作用域【指南】

lambda 值捕获([=])会复制变量,修改不影响外部

值捕获是默认行为之一,用 [=] 表示把当前作用域中所有自动变量以值方式拷贝进 lambda 闭包。这意味着:闭包内部对这些变量的修改,不会反映到外部原始变量上。

常见错误是误以为 [=] 能同步更新外部状态,比如在循环中捕获循环变量后异步修改——实际改的是副本。

  • 基本类型(intdouble)复制开销小,安全但不可反向写回
  • 大对象(如 std::vector)会被完整拷贝,可能触发深拷贝构造,注意性能
  • 若需捕获部分变量而非全部,用显式列表:[x, y][=, &z](混合捕获)
int a = 10;
auto f = [=]() { a = 20; }; // 编译失败:a 是 const 副本(C++11 默认)
auto g = [=]() mutable { a = 20; }; // OK:mutable 允许修改副本
g();
std::cout << a << "\n"; // 输出 10,外部 a 未变

lambda 引用捕获([&])共享变量,但生命周期必须足够长

引用捕获用 [&],让 lambda 内部直接持有外部变量的引用。好处是能读写原始变量,坏处是极易引发悬垂引用(dangling reference)——尤其当 lambda 被返回或用于异步场景时。

典型崩溃场景:函数返回一个捕获局部变量引用的 lambda,调用方在函数返回后执行它。

立即学习C++免费学习笔记(深入)”;

剪映专业版
剪映专业版

一款全能易用的桌面端剪辑软件

下载
  • 引用捕获不延长所捕获变量的生命周期,仅建立别名
  • 禁止捕获即将销毁的局部变量(如函数栈上临时对象)
  • 推荐只在 lambda 生命周期明确短于所捕获变量时使用,例如同一函数内立即调用
auto make_bad_lambda() {
    int x = 42;
    return [&x]() { return x; }; // 危险!x 在函数返回后销毁
}
// auto f = make_bad_lambda(); f(); // 未定义行为

混合捕获要显式声明,[=, &y][&, x] 更安全

C++ 允许混合值捕获与引用捕获,但语法有约束:不能同时用 [=][&],必须显式列出部分变量,并用 =& 标明每个捕获方式。更安全的习惯是「默认值捕获 + 显式引用」,即 [=, &y]

为什么?因为 [&, x] 表示“默认引用捕获 + 显式值捕获 x”,一旦遗漏某个需要引用的变量,它会被隐式按引用捕获,容易因生命周期问题出错;而 [=, &y] 中所有变量默认值捕获(安全),只对明确需要共享的 y 开放引用,意图清晰、风险可控。

  • [=, &y]:y 是引用,其余变量是副本
  • [&, x]:x 是副本,其余变量是引用(包括可能未声明的 this、参数等)
  • 捕获 this 时,[this] 是值捕获指针,[&] 也会捕获 this 为引用,但不等于捕获成员变量本身
int a = 1, b = 2;
auto f = [=, &b]() {
    a = 10; // 修改副本,无效
    b = 20; // 修改原始 b,生效
};
f();
std::cout << a << ", " << b << "\n"; // 输出 "1, 20"

lambda 捕获 this 的两种方式区别很大

在类成员函数中,[this][=] 都会捕获 this 指针,但语义不同:[this] 明确表示只捕获当前对象指针,不自动捕获任何成员变量;而 [=] 会尝试按值捕获所有自动变量,包括 this(即复制指针),但**不会复制成员变量**——成员仍需通过 this->member 访问,本质还是间接引用。

真正危险的是误以为 [=] 把整个对象拷贝进了 lambda。它没有。如果你在 lambda 中保存了 [=] lambda 并在对象析构后调用,访问成员仍会 crash。

  • [this]:显式、轻量,适合只读/调用成员函数
  • [=]:隐式包含 this,但易造成“以为值捕获了对象”的误解
  • 若真需要复制整个对象,应手动捕获成员变量,如 [x = x_, y = y_](C++14 起支持初始化捕获)
struct S {
    int val = 100;
    auto get_lambda() {
        return [this]() { return val; }; // OK,this 有效期间安全
        // return [=]() { return val; }; // 同样依赖 this 存活,不是值拷贝 val
    }
};
捕获的本质不是“变量内容”,而是“绑定方式”——值捕获是快照,引用捕获是链接,this 捕获只是指针。最常被忽略的,是以为 [=] 能隔离状态,其实它连成员变量都不复制。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

311

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

511

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

46

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

182

2025.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

46

2025.08.29

C++中int、float和double的区别
C++中int、float和double的区别

本专题整合了c++中int和double的区别,阅读专题下面的文章了解更多详细内容。

92

2025.10.23

lambda表达式
lambda表达式

Lambda表达式是一种匿名函数的简洁表示方式,它可以在需要函数作为参数的地方使用,并提供了一种更简洁、更灵活的编码方式,其语法为“lambda 参数列表: 表达式”,参数列表是函数的参数,可以包含一个或多个参数,用逗号分隔,表达式是函数的执行体,用于定义函数的具体操作。本专题为大家提供lambda表达式相关的文章、下载、课程内容,供大家免费下载体验。

200

2023.09.15

python lambda函数
python lambda函数

本专题整合了python lambda函数用法详解,阅读专题下面的文章了解更多详细内容。

187

2025.11.08

虚拟号码教程汇总
虚拟号码教程汇总

本专题整合了虚拟号码接收验证码相关教程,阅读下面的文章了解更多详细操作。

25

2025.12.25

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 5.3万人学习

C 教程
C 教程

共75课时 | 3.6万人学习

C++教程
C++教程

共115课时 | 9.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号