C++ 如何实现A对象随B存活而不被销毁且B无需感知A
符合约束的C++实现方案
完全可以满足需求,核心是利用std::shared_ptr的别名构造函数实现,全程不需要B类感知A类的存在,也不需要修改B类的任何代码。
方案适配性说明
- 没有对B类做任何侵入性修改,B类不会持有任何A类的指针、引用,完全符合“B类不感知A类”的核心约束
- 仅需调整A类的少量代码,不会破坏原有类的封装逻辑
具体实现步骤
1. 修改A类继承关系
要使用shared_from_this()方法,必须让A类继承自std::enable_shared_from_this<A>。注意A类必须由std::shared_ptr接管生命周期,否则调用shared_from_this()会触发未定义行为。
修改后的A类基础结构:
class A : public std::enable_shared_from_this<A> { public: A() { m_B = B::FactoryB(); } std::shared_ptr<B> getB(); private: std::shared_ptr<B> m_B; };
同时修正原B类FactoryB方法的笔误:std::shared_ptr是模板类,必须指定指向的类型,正确的B类实现为:
class B { public: static std::shared_ptr<B> FactoryB() { return std::make_shared<B>(); } // B类原有业务逻辑保持不变 };
2. 重写getB()方法
不再直接返回内部存储的m_B,改用std::shared_ptr的别名构造函数生成新的智能指针:
原参考代码存在笔误:别名构造的返回类型为
std::shared_ptr<B>,而非std::shared<B>
正确的getB()实现:
std::shared_ptr<B> A::getB() { // 别名构造函数:第一个参数是共享所有权的对象(这里是A对象的shared_ptr),第二个参数是实际指向的对象地址(内部的B对象) std::shared_ptr<B> spBAlias(shared_from_this(), m_B.get()); return spBAlias; }
实现原理
std::shared_ptr的别名构造函数有一个核心特性:返回的智能指针实际指向第二个参数的内存地址(也就是内部的B对象),但它的引用计数完全和第一个参数传入的智能指针(也就是绑定A对象的shared_from_this())共享。
这意味着只要返回的spBAlias还存活,就会持有A对象的一份强引用,A对象的引用计数不会被提前清零。
行为验证
对应给出的main函数执行流程:
- 执行
auto spA = std::make_shared<A>()时,A对象的引用计数为1 - 执行
auto spB = spA->getB()时,spB绑定A对象的引用计数,此时A的引用计数变为2,spB实际指向内部的B对象 - 执行
spA.reset()时,仅将A的引用计数从2降到1,不会销毁A对象 - 后续调用
spB->DoSomething()时,A和B对象都处于存活状态 - 当
spB被销毁时,A的引用计数降到0,此时A和内部的B对象才会被一起回收
注意事项
- 禁止在A类的构造函数中调用
getB()或shared_from_this():此时A对象还未被std::shared_ptr接管,调用会触发std::bad_weak_ptr异常或未定义行为 - 该方案完全不侵入B类,不需要在B类中引入任何A类的依赖,符合所有约束要求
内容的提问来源于stack exchange,提问作者:匿名开发者
相关产品推荐
相关产品推荐

