shared_from_this在异步回调中crash是因为对象提前销毁导致悬空引用;根本原因是未确保对象生命周期覆盖异步操作,且类必须继承enable_shared_from_this并由shared_ptr管理,不可在构造函数中调用。

为什么 shared_from_this 在异步回调里突然 crash?
因为对象在回调执行前已被销毁,而 shared_ptr 持有的是悬空引用。典型现象是程序在回调中访问 this 成员时触发 std::bad_weak_ptr 或直接段错误——根本原因是没确保对象生命周期覆盖整个异步操作周期。
关键前提:类必须继承自 std::enable_shared_from_this,且所有对该对象的持有都来自 shared_ptr(不能混用裸指针或栈对象)。
- 继承后,
shared_from_this()才能安全返回指向当前对象的shared_ptr;否则抛std::bad_weak_ptr - 如果对象是栈上创建的(比如
MyClass obj;),调用shared_from_this()必崩,不支持 - 如果对象由多个独立
shared_ptr构造(如两次make_shared),引用计数不统一,行为未定义
如何正确把 this 传进异步回调?
不是直接捕获 this,也不是传裸指针,而是用 shared_from_this() 生成一个强引用,在回调里维持对象存活。
常见错误写法:[this]() { use(*this); } —— 这只捕获了 this 指针,不延长生命周期。
立即学习“C++免费学习笔记(深入)”;
- 正确做法:在发起异步调用时,用
shared_from_this()获取shared_ptr,再把它 move 进 lambda 捕获列表 - 示例:
[self = shared_from_this()]() mutable { self->do_work(); } - 注意
mutable:因为shared_ptr的拷贝/移动在 lambda 调用时发生,需允许修改捕获值 - 如果回调是函数对象而非 lambda(如
std::function),同样要把shared_ptr作为参数显式传入
weak_from_this 什么时候比 shared_from_this 更安全?
当回调可能长期挂起、且你不想阻止对象被释放时,用 weak_ptr 避免循环引用或过度延长生命周期。
典型场景:定时器回调、网络请求未完成时对象已退出作用域、GUI 对象被用户关闭但后台任务还在跑。
- 在类内调用
weak_from_this()得到weak_ptr,传入回调 - 回调开头立刻调用
lock():成功则获得有效shared_ptr,失败说明对象已销毁,直接 return - 示例:
auto self = weak_from_this().lock(); if (!self) return; self->handle_result(); - 比无条件强引用更轻量,也避免了“对象该死不死”导致的资源滞留
容易被忽略的初始化顺序陷阱
std::enable_shared_from_this 的内部 weak_ptr 是在 shared_ptr 构造时才初始化的——不是在对象构造函数里,而是在 make_shared 完成后。
这意味着:在构造函数体内调用 shared_from_this() 是未定义行为,大概率抛 std::bad_weak_ptr。
- 绝对不要在构造函数里调用
shared_from_this()或weak_from_this() - 也不要在基类构造函数中尝试获取派生类的
shared_ptr - 如果需要在对象刚创建后立即注册回调,把注册逻辑推迟到构造完成之后(比如用工厂函数封装
make_shared+ 初始化方法)
shared_ptr 管理过,或者在构造函数里急着调 shared_from_this。










