
lambda 捕获列表写错,程序直接崩溃或读到垃圾值
捕获列表不是可有可无的语法糖,它决定 lambda 如何访问外部变量。写错最常见后果是:访问已销毁的栈变量(比如在函数返回后调用该 lambda),或者意外修改了本不该改的变量。
关键原则:按需选择捕获方式,不默认用 [=] 或 [&]。
-
[x]:值捕获单个变量x,内部存的是副本,修改不影响原变量 -
[&x]:引用捕获x,内部直接操作原变量——但必须确保x的生命周期比 lambda 长 -
[=]:隐式值捕获所有外部自动变量,但this不会被捕获(C++11);C++17 起,this仍不会被自动捕获,需显式写[=, this] -
[&]:隐式引用捕获所有外部自动变量,风险极高——只要任一变量提前析构,调用 lambda 就 UB -
[this]:显式捕获当前对象指针,用于成员函数内访问member或this->member
示例:int x = 42; auto f = [&x]() { x++; }; f(); —— 这里 x 被引用捕获,f() 执行后外部 x 变成 43;若改成 [x],则外部 x 不变。
在 std::thread 或 std::async 里传 lambda,捕获引用大概率出问题
线程异步执行时,外层函数很可能早已返回,栈上变量已被销毁。此时若 lambda 引用捕获了局部变量,就是典型的悬垂引用。
立即学习“C++免费学习笔记(深入)”;
典型错误现象:std::thread t([&val]() { use(val); }); t.detach(); —— val 是局部变量,线程可能在 val 销毁后才开始执行,use(val) 读到随机值或触发段错误。
- 安全做法:值捕获(
[val])或移动捕获([val = std::move(val)],C++14+) - 需要共享数据?改用
std::shared_ptr管理对象,然后值捕获智能指针:[ptr = std::make_shared<int>(42)]() { *ptr = 100; }</int> - 绝对不要对局部变量用
[&]启动新线程
mutable lambda 和 const 成员函数里的捕获冲突
默认 lambda 是 const callable 对象,其 operator() 是 const 成员函数。这意味着:值捕获的变量不能在 lambda 内部修改,除非加 mutable。
但加了 mutable 后,又可能和外围 const 成员函数冲突——比如你在 const 成员函数里定义 lambda 并试图修改值捕获的变量。
- 不加
mutable:[x]() { x = 10; }编译失败(x 是只读副本) - 加
mutable:[x]() mutable { x = 10; }允许修改副本,但注意:这不会影响外部x - 在 const 成员函数中,
[this]() mutable { member = 42; }依然非法——mutable只解除了 lambda 对象自身的 const 限制,不解除对this所指对象的 const 限定 - 真要改成员?得确认该成员是
mutable的,或把 lambda 放在非 const 成员函数里
C++11 到 C++20 捕获语法的兼容性坑
老项目升级编译器常在这里翻车。C++11 不支持初始化捕获(即 [x = expr]),也不支持 [...args] 包展开捕获;C++14 才引入前者,C++20 才支持后者。
常见错误现象:用 Clang 3.5 或 GCC 4.9 编译带 [x = std::move(y)] 的代码,报错 expected ‘]’ before ‘=’ token。
- 跨版本安全写法:C++11 项目避免初始化捕获,改用普通值捕获 + 构造逻辑移入 lambda 体内
-
[x{std::move(y)}]是 C++14+ 的替代写法,比[x = std::move(y)]更早可用(GCC 4.9 支持前者,但不支持后者) - 捕获 this 指针在 C++11 是隐式允许的(仅限非静态成员函数内),但显式写
[this]更清晰、更易读、且 C++20 要求显式
捕获的本质是生成一个闭包类型,它的构造时机、存储方式、是否可拷贝/移动,都受捕获方式直接影响。写的时候多问一句:这个变量生命周期够不够长?我改的是副本还是本体?编译器版本认不认识这个写法?









