[=]按值捕获变量,修改的是副本而非原变量;[&]易致悬垂引用;混合捕获仅支持[=, &x]或[&, x];mutable仅影响lambda内副本,不改变外部变量。
![c++的lambda表达式捕获列表有哪些坑? ([=]和[&]的区别)](https://img.php.cn/upload/article/001/431/639/176915850284568.png)
捕获列表写成 [=] 却意外修改了外部变量
很多人以为 [=] 是“只读复制”,其实它只是按值捕获,不代表变量不可变。如果被捕获的是一个类对象,且该类的成员函数或重载操作符能修改自身状态(比如 std::vector::push_back()),那么 lambda 内部调用这些函数时,改的是副本——但你根本意识不到这个副本的存在,更不会想到它和原始变量毫无关系。
常见错误现象:[=] 捕获了一个 std::vector,lambda 里调用了 v.push_back(42),执行完后原 vector 一点没变,还纳闷“为什么没生效”。
-
[=]对每个自动变量做拷贝构造(或移动,若满足条件),后续所有操作都作用于副本 - 如果想让 lambda 修改原始变量,必须用
[&],或者显式列出引用捕获项如[&v] - 注意:
[=]不会捕获 this 指针以外的任何隐式内容;在类成员函数中使用时,[=]默认也按值捕获*this(即复制整个对象),这通常不是你想要的
[&] 捕获导致悬垂引用(dangling reference)
[&] 看似方便,但它把所有自动变量都按引用捕获——而引用的有效性完全依赖于被引用变量的生命周期。一旦 lambda 在定义它的作用域外被调用,就极可能访问已销毁的栈内存。
典型场景:函数返回一个 lambda,里面用了 [&],调用方接收并 later 调用它:
立即学习“C++免费学习笔记(深入)”;
auto make_bad_lambda() {
int x = 10;
return [&]() { return x; }; // ❌ x 是局部变量,函数返回后即销毁
}
// 后续调用会读取垃圾值,UB-
[&]不检查变量是否“活得够久”,编译器几乎不报错(Clang/GCC 可能给 -Wreturn-stack-address 警告,但不覆盖所有情况) - 尤其危险的是捕获容器迭代器、临时字符串视图(
std::string_view)、或std::optional返回的引用::value() - 安全做法:除非明确知道 lambda 和被捕获变量共存亡(比如只在当前作用域内同步调用),否则避免全引用捕获
混合捕获 [=, &x] 的语法限制和陷阱
C++14 起支持混合捕获,但规则很严格:要么全部是值捕获,要么默认是值/引用捕获,再加显式例外。不能写成 [x, &y] 这种“部分显式值 + 部分显式引用”的形式(C++20 仍不合法)。
正确写法只有两种:
-
[=, &y]:默认按值,但y特别指定为引用 -
[&, x]:默认按引用,但x特别指定为值
错误写法示例:
int x = 1, y = 2;
auto bad = [x, &y]() { ... }; // ❌ 编译错误:C++ 不允许混用无默认的显式捕获另外注意:[=, &this] 是冗余的,因为 [=] 已隐含捕获 *this(按值),而 &this 意图捕获指针本身——但 this 是右值,不能绑定到非 const 左值引用,所以这条写法实际也通不过编译。
mutable lambda 修改按值捕获的变量,但不影响外部
默认 lambda 是 const 的:即使按值捕获了 int x,你也无法在 lambda 体内给它赋值,除非加 mutable。但这只是解除了 lambda 自身副本的 const 限定,和外部变量完全无关。
容易误解的点:
-
[x]() mutable { x = 99; }→ 改的是副本,外部x仍是原值 -
[&x]() { x = 99; }→ 直接改外部变量,无需 mutable -
[=]() mutable { /* 无法访问未捕获的变量 */ }→ 仍然只能访问捕获列表中声明的那些
真正需要 mutable 的典型场景是:内部缓存计算结果、实现伪随机数生成器的状态更新、或配合 std::function 存储可变状态的闭包——但务必清楚,这些状态全是 lambda 自己的私有副本。
最常被忽略的一点:捕获列表不是类型系统的一部分,同一个 lambda 表达式每次出现都会生成不同类型的闭包类。这意味着 auto 是最安全的推导方式;试图用 std::function 包装时,要注意值捕获带来的额外拷贝开销,尤其是捕获大对象(如 std::vector 或自定义结构体)时,[=] 可能悄悄触发深拷贝。











