为何Option1调用shared_from_this触发bad_weak_ptr崩溃,Option2正常?
Option1调用shared_from_this()时会因bad_weak_ptr导致崩溃,Option2则可正常运行。二者唯一区别是克隆对象的创建位置:一种在Clone()函数内,另一种在创建克隆的shared_ptr语句中。看似两种情况都满足shared_from_this()要求的“调用时已有shared_ptr持有当前对象所有权”的条件,实际差异出在enable_shared_from_this的初始化逻辑上。
问题代码
class Base { public: virtual Base* Clone() = 0; }; class Derived : public Base, public std::enable_shared_from_this<Derived> { public: Base* Clone() override { return new Derived(*this); } void test() { std::shared_ptr<Derived> ptr = shared_from_this(); } }; int main() { std::shared_ptr<Base> obj = std::make_shared<Derived>(); //std::shared_ptr<Base> clone = std::shared_ptr<Base>(obj->Clone()); // option 1(崩溃) std::shared_ptr<Base> clone = std::shared_ptr<Base>(new Derived(*std::static_pointer_cast<Derived>(obj))); // option 2(正常) std::shared_ptr<Derived> derived = std::static_pointer_cast<Derived>(clone); derived->test(); return 0; }
核心原因:enable_shared_from_this的初始化依赖指针静态类型
std::enable_shared_from_this内部靠一个weak_ptr跟踪对象的shared_ptr持有者,这个weak_ptr只会在第一个指向对象的shared_ptr构造时初始化,且初始化的前提是:shared_ptr的构造函数能识别到对象实际类型继承了enable_shared_from_this。
Option1崩溃的原因
obj->Clone()返回的是Base*类型指针(虽然实际指向Derived对象)。- 用这个
Base*构造std::shared_ptr<Base>时,编译器只能看到Base类型——而Base没有继承enable_shared_from_this,因此shared_ptr的构造函数不会去初始化Derived对象内部的enable_shared_from_thisweak_ptr。 - 后续调用
test()时,shared_from_this()尝试从未初始化的weak_ptr生成shared_ptr,直接触发bad_weak_ptr异常。
Option2正常的原因
new Derived(...)生成的是Derived*类型指针,随后隐式转换为Base*传给std::shared_ptr<Base>的构造函数。- shared_ptr的构造函数是模板实现,能推导传入指针的实际类型是
Derived*,发现Derived继承了enable_shared_from_this<Derived>,于是会正确初始化对象内部的weak_ptr。 - 调用
test()时,shared_from_this()可以从已初始化的weak_ptr生成合法的shared_ptr,因此正常运行。
修复Option1的正确方式
要让Option1正常工作,需要让Clone()返回的指针能让shared_ptr识别到实际类型,最简单的方法是修改Clone()返回std::shared_ptr<Base>:
class Base { public: virtual std::shared_ptr<Base> Clone() = 0; }; class Derived : public Base, public std::enable_shared_from_this<Derived> { public: std::shared_ptr<Base> Clone() override { return std::make_shared<Derived>(*this); } void test() { std::shared_ptr<Derived> ptr = shared_from_this(); } }; int main() { std::shared_ptr<Base> obj = std::make_shared<Derived>(); std::shared_ptr<Base> clone = obj->Clone(); // 现在可正常运行 std::shared_ptr<Derived> derived = std::static_pointer_cast<Derived>(clone); derived->test(); return 0; }
内容的提问来源于stack exchange,提问作者Notrum666
相关产品推荐
相关产品推荐

