使用shared_from_this时触发std::bad_weak_ptr错误的求助
我已查阅过所有关于使用shared_from_this传递已有shared_ptr实例时触发std::bad_weak_error的相关问题,但均与我的情况不符:
- 在调用shared_from_this()前,已存在该类的shared_ptr实例
- 类已公有继承std::enable_shared_from_this<>
复现代码
#include <iostream> #include <memory> class ILogger { public: virtual ~ILogger() {} virtual void Log() = 0; }; class LogManager; class Logger : public ILogger { public: Logger(std::shared_ptr<LogManager> logManager) : m_logManager(logManager) { } void Log() override { std::cout << "Dump logs"; } private: std::shared_ptr<LogManager> m_logManager; }; class ILogManager { public: virtual ~ILogManager() {} virtual std::shared_ptr<ILogger> GetLogger() = 0; }; class LogManager : public ILogManager, public std::enable_shared_from_this<LogManager> { public: virtual std::shared_ptr<ILogger> GetLogger() { return std::static_pointer_cast<ILogger>(std::make_shared<Logger>(this->shared_from_this())); } }; class LogManagerFactory { public: static ILogManager* Create() { auto logManager = new LogManager(); return logManager; } }; int main() { auto logManager = std::shared_ptr<ILogManager>(LogManagerFactory::Create()); auto logger = logManager->GetLogger(); }
错误信息
Program returned: 139 terminate called after throwing an instance of 'std::bad_weak_ptr' what(): bad_weak_ptr
问题根源
问题出在shared_ptr的构造逻辑上:你用std::shared_ptr<ILogManager>托管LogManager实例,但enable_shared_from_this<LogManager>内部的weak_ptr需要由**指向LogManager本身的shared_ptr**来初始化。当你用基类ILogManager的指针构造shared_ptr时,这个shared_ptr不会关联到LogManager继承的enable_shared_from_this中的weak_ptr,导致后续调用shared_from_this()时,内部weak_ptr未被初始化,抛出bad_weak_ptr异常。
修复方案
方案一:工厂直接返回std::shared_ptr<ILogManager>
修改LogManagerFactory的Create方法,直接创建指向LogManager的shared_ptr,这样能正确触发enable_shared_from_this的初始化:
class LogManagerFactory { public: static std::shared_ptr<ILogManager> Create() { return std::make_shared<LogManager>(); } };
方案二:转换派生类指针后构造shared_ptr
如果必须保留工厂返回原始指针的形式,在main中先将ILogManager*转换为LogManager*,再构造shared_ptr:
int main() { auto rawLogManager = LogManagerFactory::Create(); auto logManager = std::shared_ptr<LogManager>(static_cast<LogManager*>(rawLogManager)); auto logger = logManager->GetLogger(); }
原理补充
std::enable_shared_from_this的工作机制是:当第一个指向该类实例的shared_ptr<T>被创建时,它会自动初始化enable_shared_from_this内部的weak_ptr<T>。如果创建的是指向基类的shared_ptr<Base>,而enable_shared_from_this属于派生类Derived,那么基类的shared_ptr不会触发派生类中enable_shared_from_this的初始化逻辑,最终导致shared_from_this()调用失败。
内容的提问来源于stack exchange,提问作者LKB

