使用enable_shared_from_this触发bad_weak_ptr异常,如何解决?
代码背景
基类eventreceiver定义:
class eventreceiver { public: eventreceiver() = default; virtual ~eventreceiver() = default; virtual void on_quit(); };
继承自eventreceiver和std::enable_shared_from_this<engine>的engine类:
class engine : public eventreceiver, std::enable_shared_from_this<engine> { public: virtual ~engine() = default; [[nodiscard]] static std::shared_ptr<engine> create(); void init(std::string_view title, int32_t width, int32_t height, bool fullscreen = false); void add_loopable(std::shared_ptr<loopable> loopable); void run(); protected: virtual void on_quit() override; private: engine() = default; bool _running; std::list<std::shared_ptr<loopable>> _loopables; std::shared_ptr<window> _window; std::shared_ptr<renderer> _renderer; std::shared_ptr<eventmanager> _eventmanager; };
engine::init方法实现:
void engine::init(std::string_view title, int32_t width, int32_t height, bool fullscreen) { _running = true; _window = std::make_shared<window>(title, width, height, fullscreen); _renderer = _window->create_renderer(); _eventmanager = std::make_shared<eventmanager>(); _eventmanager->add_receiver(std::dynamic_pointer_cast<eventreceiver>(shared_from_this())); // 触发bad_weak_ptr异常 add_loopable(std::make_shared<framerate>()); }
问题描述
调用engine::init时,shared_from_this()触发bad_weak_ptr异常,如何正确将engine的shared_ptr传递给_eventmanager?
错误原因
std::enable_shared_from_this继承权限错误
在多继承列表中,仅第一个基类eventreceiver显式声明为public继承,第二个基类std::enable_shared_from_this<engine>默认采用private继承。而std::enable_shared_from_this要求必须公有继承,否则std::shared_ptr无法访问其内部的weak_ptr成员完成初始化,调用shared_from_this()时就会抛出异常。(潜在风险)对象未被
std::shared_ptr持有
若engine::create()方法未正确返回持有当前对象的shared_ptr,或在shared_ptr创建前调用init,也会导致shared_from_this()无法获取有效指针。
修复步骤
修正
enable_shared_from_this的继承权限
将std::enable_shared_from_this<engine>改为公有继承:class engine : public eventreceiver, public std::enable_shared_from_this<engine> { // 原有代码保持不变 };确保
create()方法正确返回shared_ptr
实现create()时,必须返回持有engine对象的shared_ptr,推荐使用std::make_shared:std::shared_ptr<engine> engine::create() { return std::make_shared<engine>(); }正确调用
init的时机
必须在shared_ptr创建完成后调用init:auto engine_inst = engine::create(); engine_inst->init("My App", 800, 600);优化指针转换(可选)
由于engine是公有继承eventreceiver,可以用static_pointer_cast替代dynamic_pointer_cast,提升效率:_eventmanager->add_receiver(std::static_pointer_cast<eventreceiver>(shared_from_this()));
内容的提问来源于stack exchange,提问作者Rodrigo

