C++ lambda捕获列表 C++ 按值捕获与引用捕获区别【闭包】
技术百科
冰火之心
发布时间:2026-01-26
浏览: 次 按值捕获[x]生成独立副本,但默认const;加mutable才可修改副本,不影响原变量,且拷贝构造函数副作用真实发生。
按值捕获([x])实际是拷贝,不是“只读副本”
很多人误以为 [x] 捕获后 x 就彻底与原变量无关、且不可修改——其实前半对,后半错。按值捕获确实会调用 x 的拷贝构造函数(或移动构造,若满足条件),生成闭包内部的独立副本;但这个副本默认是 const 的,除非 lambda 声明为 mutable。
- 不加
mutable时,即使捕获的是非 const 变量,也无法在 lambda 体内修改该副本(编译报错:assignment of read-only variable) - 加
mutable后,可修改副本,但不影响外部原始变量 - 若捕获的是类对象,且其拷贝构造函数有副作用(比如日志打印),按值捕获会真实触发它——这点常被忽略
int a = 42;
auto f = [a]() mutable { a = 99; }; // OK:修改的是副本
f();
std::cout << a << "\n"; // 输出 42,原变量未变
引用捕获([&x])绑定的是运行时对象,不是声明时快照
引用捕获不拷贝,只存一个引用,因此闭包内对 x 的读写直接作用于原始变量。但它不保证该变量在 lambda 被调用时仍有效——这是悬垂引用(dangling reference)的高发场景。
- 若 lambda 在定义它的作用域结束后仍被调用(比如返回给外层、存入容器、交给异步任务),而被捕获的变量已析构,行为未定义
- 引用捕获对临时对象极其危险:
auto f = [&s]{ return s.size(); };中若s是函数局部std::string,lambda 返回后调用必崩溃 -
[&]全局引用捕获更隐蔽:它会把所有自动变量都按引用抓进来,容易无意中延长生命周期依赖
混合捕获时,值捕获和引用捕获共存需显式指定
C++ 不允许隐式混用;必须明确写出每个捕获项。常见错误是想“大部分按引用、个别按值”,却误写成 [&, x] 或 [=, &y]——后者在 C++11/14 中非法,C++17 才支持 [=, &y],但 [&, x] 始终合法(先全部引用,再显式覆盖 x 为值捕获)。
-
[&, x]:除x外所有变量按引用捕获,x按值捕获 -
[=, &y]:C++17 起才允许,表示除y外所有变量按值捕获,y按引用捕获 - 若同时出现
x和&x,编译器报错:duplicate capture of 'x' - 捕获列表顺序不影响语义,但影响可读性;建议把易出错的引用捕获放在前面并加注释
lambda 生命周期与捕获对象生命周期不匹配是硬伤
没有垃圾回收的 C++ 里,闭包本身不管理捕获对象的生存期。按值捕获靠拷贝“脱钩”,相对安全;引用捕获则完全依赖程序员手动确保“lambda 死亡前,被引对象不能死”。这在回调、线程、信号槽等场景极易翻车。
- 跨函数传 lambda?检查所有引用捕获变量是否至少活到 lambda 执行完
- 用
std::thread拆包 lambda?别直接传[&x],改用[x]或std显式控制
::ref(x)
- 考虑用
std::shared_ptr包裹共享数据,再按值捕获指针,比裸引用更可控
真正难的不是语法,而是判断“这里该用哪种捕获”——得看变量谁拥有、谁销毁、lambda 谁调用、何时调用。写完 lambda,先盯三秒捕获列表,问自己:这个变量,三年后还在不在?
# 的是
# 放在
# 会把
# 这是
# 很多人
# 还在
# 无意中
# 哪种
# 这在
# auto
# 对象
# c++
# String
# 区别
# 指针
# 构造函数
# 报错
# 线程
# 异步
# 作用域
# Thread
# 闭包
# Lambda
# const
# mutable
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- PythonWeb前后端整合项目教程_FastAP
- Win11怎么更改计算机名_Windows11系统
- c++怎么实现大文件的分块读写_c++ 文件指针s
- mac怎么看硬盘大小_MAC查看磁盘存储空间与文件
- Mac怎么进行语音输入_Mac听写功能设置与使用【
- 如何使用Golang处理静态文件缓存_提高页面加载
- Python多进程教程_multiprocessi
- Win10怎样安装PPT模板_Win10安装PPT
- php中作用域操作符能访问私有静态属性吗_访问权限
- 如何使用Golang实现云原生应用弹性伸缩_自动应
- Win11相机打不开提示错误怎么修_相机权限开启与
- 如何使用Golang实现文件加密_Golang c
- 如何在Golang中理解指针比较_Golang地址
- Win11怎么关闭触摸屏_禁用Win11笔记本触摸
- Win11怎么更改管理员名字 Win11修改账户名
- Win10怎样设置多显示器_Win10多显示器扩展
- 如何在 VS Code 中正确配置并使用 NumP
- 如何在 Go 中可靠地测试含 time.Time
- 如何在Golang中优化文件读写性能_使用缓冲和并
- php嵌入式日志记录怎么实现_php将硬件数据写入
- 如何使用Golang table-driven f
- Win11任务栏天气怎么关闭 Win11隐藏天气小
- c++怎么使用std::tuple存储多元组数据_
- Win11如何设置自动关机 Win11定时关机命令
- Win11怎么设置指纹解锁 Win11笔记本录入指
- Win11 explorer.exe频繁崩溃_修复
- Windows10系统怎么查看CPU核心数_Win
- Python网络超时处理_健壮性设计说明【指导】
- Windows 11无法安全删除U盘提示设备正在使
- 如何使用Golang处理网络超时错误_Golang
- php485在macos下怎么配置_php485
- Mac如何设置动态壁纸?(让桌面动起来)
- php增删改查需要哪些扩展_开启mysqli或pd
- Python异步网络编程_aiohttp说明【指导
- Win11输入法切换快捷键怎么改_Windows
- Win11怎么关闭定位服务 Win11禁止应用获取
- Python正则表达式实战_模式匹配说明【教程】
- Python实现图数据库操作_Neo4j核心CRU
- 如何解决Windows时间不准的问题?(自动同步设
- Windows笔记本无法进入睡眠模式怎么办?(电源
- Win11怎么设置右键刷新选项_Windows11
- LINUX如何开放防火墙端口_Linux fire
- c# 在ASP.NET Core中管理和取消后台任
- Win11怎么设置默认浏览器Chrome_Wind
- Python 模块的 __name__ 属性如何由
- Win11怎么自动隐藏任务栏_Win11全屏显示设
- 如何在Golang中实现WebSocket广播_使
- 如何用正则表达式精确匹配“start”到“end”
- php删除数据怎么清空表_truncate与del
- Go语言中slice追加操作的底层共享机制详解


QQ客服