7

简短版本:
在现代 C++ 中使用非智能指针是否有任何可接受的理由?

长版:
我们有一个包含大量旧 C++ 代码的庞大产品,现在我们正试图将其重构到现代 C++ 时代。除了所有老式代码之外,还有大量指针在传递(主要是使用 SAL 注释来提供某种安全感),我想知道我们是否应该将它们全部更改为智能指针,或者保留其中一些?
尝试转换其中一些代码时,我最终得到了一个可以简单地争论为过度使用智能指针的代码。

所以问题是:是否存在过度使用智能指针这样的事情?
或者换句话说:这些天对于非智能指针是否有任何可接受的场景?

4

5 回答 5

5

智能指针(unique_ptrshared_ptr)应该是 OWNING 指针(即负责对象的销毁)。使用它们的底线是new应将由创建的任何对象尽快推入一个unique_ptrASAP,以防止内存泄漏。之后,unique_ptr应该最终被移动:

  • 要么进入shared_ptr如果所有权应该共享,
  • 或进入unique_ptrif 所有权由范围(块的或对象的生命周期)确定。

releases 应该很少见。如果您的代码传递非拥有指针,这些应该是:

  • 原始指针(如果可能) null(由 获得get
  • 参考资料(如果不是) null,(由 获得get
  • unique_ptr如果调用的目的是转移所有权,则按价值计算。(在这种情况下,您需要移动它们)

工厂方法应该unique_ptr按值返回 s。(因为那样的话,如果你不分配工厂方法的返回值,对象会立即被释放)

并查看 Ali 关于处理遗留代码的一些哲学观点的链接的答案。(我完全同意)

于 2013-10-17T08:33:14.003 回答
4

简短版本:
在现代 C++ 中使用非智能指针是否有任何可接受的理由?

简短的回答:

当然,如果他们只是用于观察,也就是说,他们不拥有指针。但是,即使在这种情况下,也要尝试使用引用而不是指针;仅当您确实需要使它们成为可选时才使用指针(null_ptr例如,使用然后重新分配初始化)。

长版:
我们有一个包含大量旧 C++ 代码的庞大产品,现在我们正试图将其重构到现代 C++ 时代。[...]

长答案:

当我阅读这些行时,我想到了这个答案:

我希望我能不止一次地支持这个答案。我会引用:“[...] 对于我们所做的每一个重构因素,我们都可以证明‘这个特定的改变将使我们现在正在做的实际任务更容易’。而不是‘这对于未来的工作来说现在更清洁了’。”

长话短说,除非你真的需要,否则不要进行大的重构。

所以问题是:是否存在过度使用智能指针这样的事情?

在我看来,std::shared_ptr是过度使用。它使用起来非常舒适,它给您一种无需考虑所有权问题的错觉。但这还不是全部。我完全同意Sean Parent的观点:“共享指针与全局变量一样好。” 共享指针还会引入非常困难的所有权问题等。

另一方面,如果您需要在堆上分配一些东西,请使用unique_ptr. 如果你真的需要堆分配,你不能过度使用它。以我的经验,使用unique_ptr也可以使代码更清晰、更容易理解,因为所有权问题变得不言自明。

Sean Parent 就如何避免/减少指针的使用进行了有趣的讨论:

希望这可以帮助。

于 2013-10-17T16:20:15.010 回答
3

是的,原始指针仍然可以用作“可选引用”。即 aT*类似于 a T&。两者都不意味着所有权,但 aT*可以是 a nullptr

于 2013-10-17T09:02:27.120 回答
0

在这里查看演讲:http: //channel9.msdn.com/Events/GoingNative/2013(尤其是 Stroustrup 的演讲)。

简短的回答是否定的,假设“现代 C++”>= c++11

长的答案是,情况并非总是如此,尝试重组一个大型项目几乎总是很困难。我们思考问题的方式受到我们解决问题的工具的限制。在许多情况下,当使用指针比尝试将基本逻辑重新表达为类和智能指针友好更有意义时,进行此类重构。我认为智能指针被过度使用的情况较少,而类使用不足的情况更多。YMMV ;-)

于 2013-10-17T03:21:37.953 回答
0

当然,现代 C++ 中有原始指针的用例:

  • 必须像纯 C 一样编译的接口(尽管实现本身可能会使用那些 C++ 特性,这些特性也不是 C 特性,如类或智能指针)
  • 代码非常低级,非常低级,即使是最简单的智能指针也被证明是重量级的

当然,这些是相当罕见的情况,到目前为止,指针的大多数用例智能指针应该适用于新代码,但是:

如果现有代码在原始指针上运行良好,为什么要花时间重写它并冒险在使用版本将其转换为智能指针时添加错误?

不要重构代码,这很好,只是因为新代码更好地遵循现代编程标准。这些编程标准并不是为了它们本身而存在,而是为了让一些代码的工作更容易,所以不要进行重构,这将花费你更多的时间,而不是它们在未来为你节省的时间。

这意味着:如果要花费更多时间来检查这些指针中的哪些可以安全地转换为智能指针,哪些不能并寻找您的重构可能引入的错误,那么您将能够保存由于重构而导致的未来维护工作,那么干脆不要重构并让它保持原样。

如果重构比仅代码库的某些部分节省更多时间,那么请考虑仅重构代码库的那些部分。

于 2013-10-17T15:58:04.613 回答