多个对象共用同一shared_ptr的正确方式?解决运行时错误的方案
最佳处理方式
直接传递shared_ptr的拷贝(不使用std::move)即可,这也是shared_ptr设计的核心用法——通过拷贝操作安全增加引用计数,让A和B共享同一个C对象的所有权。
修改后的main函数代码:
int main() { std::shared_ptr<C> c = std::make_shared<C>(); A a(c); // 拷贝shared_ptr,引用计数变为2 B b(c); // 再次拷贝,引用计数变为3 return 0; }
另外,A和B的构造函数可以保持现有写法(传值后用std::move转移到成员变量,能避免额外拷贝,属于合理优化),也可以改成接收const引用再拷贝,效果一致:
// A的构造函数可选写法(B同理) A(const std::shared_ptr<C>& c) : c_(c) {}
可选方案
除了上述最佳方案,还有几种场景化的处理方式:
提前拷贝后移动:如果一定要用
std::move,可以先拷贝出独立的shared_ptr再转移给每个对象,避免原指针被掏空:int main() { std::shared_ptr<C> c = std::make_shared<C>(); std::shared_ptr<C> c_for_a = c; A a(std::move(c_for_a)); std::shared_ptr<C> c_for_b = c; B b(std::move(c_for_b)); return 0; }这种写法冗余,仅适合某些特殊的所有权转移逻辑场景,日常不推荐。
使用
weak_ptr(无需所有权时):如果A或B不需要持有C的所有权,只是需要在C存活时访问它,可以改用std::weak_ptr,避免不必要的引用计数持有:class A { public: A(std::weak_ptr<C> c) : c_(std::move(c)) {} void access_c() { if (auto locked = c_.lock()) { // 安全访问C对象,locked是临时的shared_ptr } } private: std::weak_ptr<C> c_; }; // main函数中 std::shared_ptr<C> c = std::make_shared<C>(); A a(c); // shared_ptr可隐式转换为weak_ptr B b(c);传递原始指针(不推荐):如果能严格保证C的生命周期长于A和B,可以传递原始指针,但这种方式完全手动管理生命周期,极易出现悬空指针问题,仅适合极端可控场景。
是否必须为A和B各创建一个C的shared_ptr?
不需要。shared_ptr的核心价值就是让多个智能指针共享同一个对象的所有权,通过引用计数自动管理对象生命周期。只要拷贝shared_ptr,A和B的成员c_就会指向同一个C对象,直到所有shared_ptr都被销毁,C才会被自动释放。
只有当你需要A和B各自拥有独立的C实例时,才需要为它们分别创建shared_ptr(比如调用两次std::make_shared<C>()),但这显然不是当前代码的需求——当前问题是误用std::move导致指针被转移为空,而非需要独立的C对象。
内容的提问来源于stack exchange,提问作者Huazhe Yin

