按值捕获[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 死亡前,被引对象不能死”。这在回调、线程、信号槽等场景极易翻车。
立即学习“C++免费学习笔记(深入)”;
- 跨函数传 lambda?检查所有引用捕获变量是否至少活到 lambda 执行完
- 用
std::thread拆包 lambda?别直接传[&x],改用[x]或std::ref(x)显式控制 - 考虑用
std::shared_ptr包裹共享数据,再按值捕获指针,比裸引用更可控
真正难的不是语法,而是判断“这里该用哪种捕获”——得看变量谁拥有、谁销毁、lambda 谁调用、何时调用。写完 lambda,先盯三秒捕获列表,问自己:这个变量,三年后还在不在?










