为何用make_shared创建对象仍触发std::bad_weak_ptr异常?
问题根由 & 解决办法
为啥会抛std::bad_weak_ptr?
哪怕你用std::make_shared创建对象,只要在构造函数里调用shared_from_this(),必然会触发这个异常——因为make_shared的执行顺序是:先分配内存、构造对象,之后才会初始化enable_shared_from_this内部的weak_ptr。构造函数运行时,这个weak_ptr还是空的,调用shared_from_this()自然会报错。
另一种可能是对象已经被析构后再调用shared_from_this(),但结合你用make_shared的场景,大概率是第一种情况导致的。
怎么解决?
1. 把异步启动逻辑从构造函数里拆出来
别在构造函数里提交异步任务,单独写一个start()方法,等对象被shared_ptr持有之后再调用这个方法:
class MyAsyncObj : public std::enable_shared_from_this<MyAsyncObj> { public: // 构造函数只做基础初始化,绝不碰异步操作 MyAsyncObj(boost::asio::io_context& io_ctx) : io_ctx_(io_ctx) {} // 专门的启动方法,此时对象已经被shared_ptr持有 void start() { auto self = shared_from_this(); // 这里调用绝对安全 io_ctx_.post([self]() { self->doAsyncStuff(); }); } private: void doAsyncStuff() { // 后续异步操作继续用shared_from_this()获取自身引用,保证对象不被提前析构 auto self = shared_from_this(); io_ctx_.post([self]() { // 你的业务逻辑... }); } boost::asio::io_context& io_ctx_; }; // 调用方式 auto obj = std::make_shared<MyAsyncObj>(io_ctx); obj->start(); // 必须等shared_ptr创建完成后再调用start
2. 所有异步回调必须持有shared_ptr
不管是什么异步任务,只要提交到io_context,回调里一定要捕获shared_from_this()拿到的self。这样只要有未完成的异步任务,对象就会被shared_ptr持有,不会被析构;等所有回调执行完毕,没有shared_ptr持有它时,对象会自动销毁,完全符合你的需求。
和Boost.Beast示例的差异
Boost.Beast的示例(比如HTTP服务端/客户端)全都是先创建shared_ptr对象,再启动异步流程的设计:
- 构造函数只初始化套接字、上下文这类资源,绝不触发异步操作
- 调用
start()或者run()这类方法时,才通过shared_from_this()获取自身引用提交任务 - 所有异步回调都会捕获
shared_ptr,把对象的生命周期和异步任务绑定在一起
这种设计从根源上避免了构造函数里调用shared_from_this()的坑,这就是你能正常运行Beast示例但自己代码出问题的核心原因。
内容的提问来源于stack exchange,提问作者Stewart
相关产品推荐
相关产品推荐

