现代 C++ 开发中,过度使用 shared_ptr 是否已经成为了一种新的“代码恶臭”?

是的,在现代 C++(C++11 及以后)开发中,过度使用 std::shared_ptr 确实被许多专家和社区视为一种“代码恶臭”(code smell),甚至被比作“穷人的垃圾回收”(poor man’s GC)或“隐形的全局变量”。

为什么过度使用 shared_ptr 被视为问题?

shared_ptr 的核心是共享所有权(shared ownership)和引用计数机制,这带来了以下缺点:

  • 性能开销:引用计数需要原子操作(线程安全),拷贝/析构时有额外代价。相比 unique_ptr 或普通引用/指针,慢得多,尤其在高频操作或实时系统中。
  • 内存开销:每个 shared_ptr 需要额外控制块(引用计数 + 删除器),通常是两个指针大小(16 字节 + 控制块)。
  • 循环引用风险:容易导致内存泄漏(需用 weak_ptr 打破循环,但这增加了复杂性)。
  • 所有权模糊:共享所有权让代码难以推理对象的生命周期,谁负责释放?何时释放?这违背了现代 C++ 强调的“明确所有权”(clear ownership)。
  • 设计问题信号:如果到处用 shared_ptr,往往表示设计不良——本该用值语义、唯一所有权或观察者模式,却懒惰地用共享来“延长生命周期”。

C++ Core Guidelines(由 Bjarne Stroustrup 等维护的官方指南)明确建议:

  • 优先用 unique_ptr 表示独占所有权(R.21)。
  • 只在真正需要共享所有权时用 shared_ptr(作为最后手段)。
  • 函数参数:如果不转移所有权,用普通指针(T*)或引用(T&);如果可能保留拷贝,用 const shared_ptr<T>&
  • Sean Parent(Adobe C++ 专家)曾说:“shared_ptr 就像全局变量一样糟糕。”

Reddit 和 Stack Overflow 上常见讨论(如 2024-2025 的帖子)也指出:许多代码像“Java 风格的 C++”,到处堆 shared_ptr,导致“Java-in-C++”式的滥用。甚至有观点认为,如果你的代码需要大量 shared_ptr,很可能设计有问题——应该重构为层次结构、值语义或 unique_ptr + 观察者。

什么时候应该用 shared_ptr?

只有在真正共享所有权的场景:

  • 对象生命周期不由单一所有者控制(如多线程共享资源、图结构中的节点)。
  • 需要弱引用打破循环(配合 weak_ptr)。
  • 工厂函数返回共享对象。

否则:

  • 用值语义(直接对象)。
  • unique_ptr(独占所有权,可移动)。
  • 用普通引用/指针(非拥有,仅观察)。

总结与建议

过度使用 shared_ptr 已成现代 C++ 中的常见反模式,尤其在新手从 Java/Python 转来时。社区共识是:它不是默认选择,而是例外。优先明确所有权、减少动态分配,能显著提升代码可读性、性能和安全性。

如果你在项目中看到到处是 shared_ptr,建议审视设计——很可能有更好的方式。参考 C++ Core Guidelines 的智能指针部分,会很有帮助。

文章已创建 4298

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部