专门针对指针、this、异步、多线程、悬空指针避坑,直接照着写就不会错

一、先搞懂 4 种基础捕获区别

[] 不捕获任何变量
[&] 全部引用捕获 → 最危险,极易悬空
[=] 全部值捕获
普通变量:拷贝一份,安全
指针 /this:只拷贝地址!不是拷贝对象
[this] 捕获当前对象指针

二、最容易踩坑的误区(必看)

[=] 不是拷贝对象,只是拷贝 this 指针
对象销毁 → Lambda 直接野指针崩溃
值捕获指针 = 拷贝指针地址
依然能修改原对象内容 *p
引用捕获 [&] + 异步 / 延时执行 = 大概率悬空指针
循环里用 [&] 捕获循环变量,全部会变成最后一个值

三、安全捕获标准写法(直接抄)

  1. 普通局部变量
    不想改原值:[a] 值捕获 ✅ 安全
    想改原值:[&a] 引用捕获
    仅限同步立即执行,不能异步存起来

  2. 捕获指针(裸指针)
    永远不推荐裸指针进 Lambda
    非要用:只允许立即执行,不能存起来延时调用

  3. 智能指针(最安全)
    unique_ptr 移动捕获
    [p = std::move(ptr)]() { ... }
    shared_ptr 值捕获
    [ptr]()

✅ 自动续命,线程 / 异步随便用,不会悬空

  1. 类成员 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;});

  1. 多线程 / 异步回调 / 定时器
    绝对禁止:引用捕获局部变量 & 裸指针
    只允许两种:

    值捕获普通变量
    shared_ptr 或者 拷贝 *this

四、一句话判断会不会崩

只要满足下面任意一条,就会悬空指针

Lambda 生命周期 > 被捕获变量生命周期
引用捕获了局部变量,还存起来晚点执行
捕获 this,原对象被析构了
裸指针被 delete 了,Lambda 还在用

五、捕获选择口诀

马上就执行:随便捕
要存起来晚点跑:不用引用,只用值
涉及对象 this:要么拷贝 *this,要么 shared_ptr
指针一律智能指针,不碰裸指针
循环捕获一定值捕获

六、最简推荐规范(日常直接遵守)

优先 [] 明确捕获,少用 [=] [&] 全局捕获
异步 / 线程回调:禁用 [&]
类里写回调:优先 [self=*this]
指针一律用 shared_ptr /unique_ptr
不确定安不安全,就值捕获,永远不会错

你要的话,我再给你整理一版超精简背诵版,方便你面试直接背。

posted on 2026-05-20 11:10  keleman  阅读(23)  评论(0)    收藏  举报