使用std::shared_ptr保存对象引用的正确方式及带&与不带&的区别
1. 用std::shared_ptr保存对象引用的正确姿势
如果你希望类B能和其他代码一起管理对象A的生命周期(也就是共享所有权),**直接把std::shared_ptr作为成员变量存储(不带引用符号)**是最稳妥、最常用的做法。
举个正确的例子:
class A{}; class B { private: std::shared_ptr<A> obj; // 直接存shared_ptr对象 public: // 构造函数接收shared_ptr,拷贝后引用计数自动+1 B(std::shared_ptr<A> r) : obj(r) {} }; int main() { std::shared_ptr<A> a(new A()); std::unique_ptr<B> b(new B(a)); // 此时a和b->obj都持有A的引用,只有两者都销毁,A才会被释放 std::cin.get(); return 0; }
这种方式下,B的成员obj会和传入的a共享A的所有权,引用计数会正确增减,完全不用担心A被意外销毁。
如果你的场景是不需要共享所有权,只是想临时用一下A(但要确保用的时候A还活着),那应该用std::weak_ptr,而不是普通引用——weak_ptr可以随时检查对象是否存活,避免悬空引用的风险。
2. 带&和不带&保存std::shared_ptr的核心区别
咱们直接结合你给的代码分析:
不带&的情况(std::shared_ptr obj;)
- 这是存储一个完整的shared_ptr对象,不是引用。当你把构造函数的参数
r赋值给obj时,会触发shared_ptr的拷贝构造,A的引用计数会加1。 - 好处是:B的成员完全独立管理A的生命周期,哪怕原来的
a被销毁了,只要b还在,A就不会被释放,绝对不会出现悬空问题。 - 这是shared_ptr的标准用法,适合绝大多数需要共享所有权的场景。
带&的情况(std::shared_ptr& obj;)
- 这是存储一个shared_ptr的引用,它不会创建新的shared_ptr,也不会增加A的引用计数,只是绑定到一个已存在的shared_ptr实例上。
- 但你的代码里藏着一个致命bug:构造函数的参数是
std::shared_ptr<A> r(值传递),这意味着r是main里a的临时拷贝。构造函数执行完之后,r就会被销毁,此时obj就变成了悬空引用——指向一个已经不存在的shared_ptr,后续任何对obj的操作都会导致未定义行为(比如程序崩溃、内存错乱)。 - 就算你把构造函数改成
B(std::shared_ptr<A>& r)(左值引用传递),让obj绑定到main里的a,依然有风险:如果main里的a在b之前被销毁(比如提前释放),obj同样会变成悬空引用,而且编译器不会给你任何提示。 - 这种用法几乎没有常规适用场景,除非你能100%保证被引用的shared_ptr生命周期绝对长于B的实例,并且完全不需要共享所有权——但哪怕这种情况,用
std::weak_ptr也比引用安全得多。
一句话总结区别
- 不带&:拥有共享所有权,安全可靠,是shared_ptr的常规操作。
- 带&:只是“借”用别人的shared_ptr,不参与生命周期管理,极易踩悬空引用的坑,非必要绝对别用。
内容的提问来源于stack exchange,提问作者philips_dvd
相关产品推荐
相关产品推荐

