C++类方法执行时智能指针提前释放对象引发崩溃的解决方案咨询
C++智能指针回调场景自销毁崩溃问题解决方案
你遇到的是C基于引用计数的智能指针的经典场景问题:回调方法执行过程中,内部操作清除了持有当前对象的最后一个shared_ptr,导致对象在方法执行完成前就被析构。Java不会触发该问题是因为JVM GC采用可达性扫描策略,执行栈上的this指针属于GC根引用,方法执行完前不会回收当前对象;而C shared_ptr计数归零就会立即销毁对象,不管方法是否还在执行。
以下是C++社区公认的成熟解决方案:
方案1:使用enable_shared_from_this延长生命周期(改动最小、最常用)
这是这类回调场景的标准解决方案,仅需两步修改:
- 让
RemoteSystemDisconnectionHandler继承std::enable_shared_from_this模板类 - 在
HandleDisconnection方法第一行获取自身的shared_ptr临时引用,拉高引用计数
修改后的核心代码:
// 继承enable_shared_from_this模板 class RemoteSystemDisconnectionHandler : public DisconnectionHandler, public std::enable_shared_from_this<RemoteSystemDisconnectionHandler> { public: explicit RemoteSystemDisconnectionHandler(const std::shared_ptr<Closeable>& closeable_remote_system, Notifier* notifier) : closeable_remote_system_(closeable_remote_system), notifier_(notifier) {} ~RemoteSystemDisconnectionHandler() { printf("Destructed.\n"); } void HandleDisconnection() override { // 第一行先获取自身引用,引用计数+1,方法执行完前不会被销毁 auto self = shared_from_this(); this->closeable_remote_system_->Close(); printf("Closed.\n"); this->notifier_->OnDisconnection(); printf("Notified.\n"); } private: const std::shared_ptr<Closeable> closeable_remote_system_; Notifier* const notifier_; };
修改后程序会正常输出:
Closed. Disconnected. Notified. Destructed.
完全符合预期。
方案2:调整所有权结构
当前所有权链为RemoteSystem -> ReceiveDataEventHandler -> RemoteSystemDisconnectionHandler,清掉EventHandler就会直接释放DisconnectionHandler。可调整为RemoteSystem同时持有DisconnectionHandler的shared_ptr,避免所有权被单一节点控制:
class RemoteSystem : public Closeable { public: void SetHandlers(const std::shared_ptr<EventHandler>& event_handler, const std::shared_ptr<DisconnectionHandler>& dis_handler) { this->receive_data_event_handler_ = event_handler; this->disconnection_handler_ = dis_handler; } void Close() override { this->receive_data_event_handler_ = nullptr; // DisconnectionHandler可等RemoteSystem自身销毁时再释放 } // 其余逻辑不变 private: std::shared_ptr<EventHandler> receive_data_event_handler_; std::shared_ptr<DisconnectionHandler> disconnection_handler_; };
该方案适合所有权结构可调整的场景,更符合依赖注入的设计规范。
方案3:异步延迟释放资源
如果业务允许异步处理,可以把Close操作和资源清理丢到异步队列执行,等当前回调完全执行完成后再清理引用,也可以避免提前销毁问题。
注意事项
- 继承
enable_shared_from_this的类必须全程用shared_ptr管理实例,不能在栈上创建,否则调用shared_from_this会触发未定义行为 - 不要在构造函数中调用
shared_from_this,此时对象还未完成构造,shared_ptr引用计数未初始化
内容的提问来源于stack exchange,提问作者zenno2
相关产品推荐
相关产品推荐

