不能直接在类里存 shared_ptr,因为构造函数执行时对象尚未被shared_ptr管理,调用shared_from_this()会抛出std::bad_weak_ptr;必须通过make_shared创建对象并确保enable_shared_from_this正确继承后,在构造完成后才可安全调用。

为什么不能直接在类里存 shared_ptr<this></this>
因为构造函数执行时,对象还没被任何 shared_ptr 管理,此时调用 shared_from_this() 会抛出 std::bad_weak_ptr。你不能在构造函数里写 self = shared_from_this() —— 这不是语法错误,而是逻辑死锁:要生成 shared_ptr,得先有控制块;而控制块只有在首次用 make_shared 或 shared_ptr 构造时才创建。
常见错误现象:std::bad_weak_ptr 异常在首次调用 shared_from_this() 时崩溃,尤其多线程环境下容易误判为竞态,其实是根本没正确初始化。
- 必须用
std::make_shared<myclass>()</myclass>(而非new MyClass+ 手动构造shared_ptr)才能保证控制块与对象内存布局合一,这是enable_shared_from_this正常工作的前提 - 继承
std::enable_shared_from_this<myclass></myclass>后,shared_from_this()才能安全访问内部的weak_ptr控制块 - 该基类不管理生命周期,只提供“从已存在
shared_ptr派生新副本”的能力
enable_shared_from_this 的正确初始化姿势
核心原则:对象必须**已经处于某个 shared_ptr 管理之下**,才能调用 shared_from_this()。这意味着所有“自引用存储”行为都得发生在构造完成之后。
典型安全做法是提供一个静态工厂函数:
class Node : public std::enable_shared_from_this<node> {
public:
std::shared_ptr<node> self;
static std::shared_ptr<node> create() {
auto ptr = std::make_shared<node>();
ptr->self = ptr; // ✅ 此时 ptr 已持有控制块
return ptr;
}
private:
Node() = default; // 防止外部 new
};
</node></node></node></node>
- 禁止在构造函数体、成员初始化列表中调用
shared_from_this()或self = shared_from_this() - 如果类需要“自我注册到某全局容器”,务必确保注册动作由外部调用方在
make_shared返回后触发,而不是在构造中隐式完成 - 使用
make_shared是硬性要求;用shared_ptr{new Node}会导致shared_from_this()永远失败
存储自身引用的实际用途和陷阱
最常见场景是回调绑定、异步任务、观察者模式中需要确保对象存活——比如 std::async 或 std::bind 捕获 this 时,裸指针无法延寿,而 shared_from_this() 可以。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
但要注意:循环引用风险极高。例如 A 存 B 的 shared_ptr,B 又通过 self 持有 A 的 shared_ptr,两者将永远无法析构。
- 优先用
weak_ptr存储反向引用(如观察者列表里存weak_ptr<observer></observer>),只在真正需要延长生命周期时才提升为shared_ptr - 若必须存
shared_ptr<this></this>,务必确认该引用是临时的、有明确释放时机的(如事件处理器执行完立刻清空) - 调试时可用
ptr.use_count()检查是否意外堆积引用,特别是涉及 lambda 捕获或信号槽机制时
多继承或模板参数不匹配导致的静默失败
如果你的类继承了多个基类,或用了模板别名/typedef,enable_shared_from_this 的模板参数必须与实际类型完全一致。否则 shared_from_this() 返回的是错误类型的 shared_ptr,编译可能通过,但运行时行为未定义。
例如:
class Base : public std::enable_shared_from_this<base> { ... };
class Derived : public Base { ... }; // ❌ Derived::shared_from_this() 返回 shared_ptr<base>
- 子类需显式继承
std::enable_shared_from_this<derived></derived>,不能依赖父类继承 - 模板类中注意:若
template<typename t> class Wrapper : public enable_shared_from_this<wrapper></wrapper></typename>写成Wrapper<t></t>才对 - Clang/GCC 在 C++17 后会对不匹配的模板参数发出
-Wweak-vtables类似警告,但不强制报错,容易遗漏
真正麻烦的从来不是怎么写那行 self = shared_from_this(),而是想清楚这个 self 在哪一刻被创建、在哪一刻被释放、有没有其他地方悄悄持有了它。很多循环引用问题,在第一次把 shared_ptr 塞进容器或 lambda 时就埋下了。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










