专门针对指针、this、异步、多线程、悬空指针避坑,直接照着写就不会错
一、先搞懂 4 种基础捕获区别
[] 不捕获任何变量
[&] 全部引用捕获 → 最危险,极易悬空
[=] 全部值捕获
普通变量:拷贝一份,安全
指针 /this:只拷贝地址!不是拷贝对象
[this] 捕获当前对象指针
二、最容易踩坑的误区(必看)
[=] 不是拷贝对象,只是拷贝 this 指针
对象销毁 → Lambda 直接野指针崩溃
值捕获指针 = 拷贝指针地址
依然能修改原对象内容 *p
引用捕获 [&] + 异步 / 延时执行 = 大概率悬空指针
循环里用 [&] 捕获循环变量,全部会变成最后一个值
三、安全捕获标准写法(直接抄)
-
普通局部变量
不想改原值:[a] 值捕获 ✅ 安全
想改原值:[&a] 引用捕获
仅限同步立即执行,不能异步存起来 -
捕获指针(裸指针)
永远不推荐裸指针进 Lambda
非要用:只允许立即执行,不能存起来延时调用 -
智能指针(最安全)
unique_ptr 移动捕获
[p = std::move(ptr)]() { ... }
shared_ptr 值捕获
[ptr]()
✅ 自动续命,线程 / 异步随便用,不会悬空
- 类成员 this 捕获(重中之重)
危险写法(别用)
[=](){ ... } // 等价 [this],对象销毁就崩
[&]()
安全写法①:仅临时用,对象肯定不销毁
[this](){ ... }
安全写法②:让 Lambda 自己存一份对象(最稳)
[self = *this]() {
// 访问 self.成员,和原对象彻底无关
}
C++14 及以上通用,完全不怕原对象销毁
5. 循环里存 Lambda
错误:
for (int i=0; i<n; i++) {
vec.push_back([&](){cout<<i;}); // 全错
}
正确:
vec.push_back([i](){cout<<i;});
-
多线程 / 异步回调 / 定时器
绝对禁止:引用捕获局部变量 & 裸指针
只允许两种:值捕获普通变量
shared_ptr 或者 拷贝 *this
四、一句话判断会不会崩
只要满足下面任意一条,就会悬空指针
Lambda 生命周期 > 被捕获变量生命周期
引用捕获了局部变量,还存起来晚点执行
捕获 this,原对象被析构了
裸指针被 delete 了,Lambda 还在用
五、捕获选择口诀
马上就执行:随便捕
要存起来晚点跑:不用引用,只用值
涉及对象 this:要么拷贝 *this,要么 shared_ptr
指针一律智能指针,不碰裸指针
循环捕获一定值捕获
六、最简推荐规范(日常直接遵守)
优先 [] 明确捕获,少用 [=] [&] 全局捕获
异步 / 线程回调:禁用 [&]
类里写回调:优先 [self=*this]
指针一律用 shared_ptr /unique_ptr
不确定安不安全,就值捕获,永远不会错
你要的话,我再给你整理一版超精简背诵版,方便你面试直接背。
浙公网安备 33010602011771号