在现代C ++中使用非智能指针

时间:2013-10-17 03:08:57

标签: c++ pointers c++11 refactoring

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

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

所以问题是:是否存在使用智能指针的问题? 换句话说:这些天非智能指针是否有任何可接受的场景?

5 个答案:

答案 0 :(得分:5)

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

  • 如果要共享所有权,则为<{1}},
  • 如果所有权由范围(块或对象的生命周期)确定,则为
  • shared_ptr

unique_ptr应该很少见。如果您的代码通过非拥有指针,则应该是:

  • 原始指针,如果它们可能是release,(由null获得)
  • 引用,如果它们可能不是get,(由null获得)
  • 如果通话目的是转让所有权,则
  • get按值计算。 (在这种情况下,你需要移动它们)

工厂方法应按值返回unique_ptr。 (因为那样,如果不指定工厂方法的返回值,则立即取消分配对象)

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

答案 1 :(得分:2)

是的,原始指针仍然用作“可选参考”。即T*T&类似。两者都不暗示所有权,但T*可以是nullptr

答案 2 :(得分:2)

  

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

简答:

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

  

长版:
  我们有一个巨大的产品,包含很多旧的C ++代码,现在我们正在尝试将它重构为现代C ++时代。 [...]

答案很长:

在阅读这些内容时,我想到了这个答案:

我希望我能不止一次地回答这个问题。我会引用:“[...]对于我们已经提出的每个重新因素,我们可以证明'这个具体的变化将使我们现在正在做的实际任务变得更容易'。而不是'现在这对于未来的工作更加清洁”“。

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

  

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

在我看来,std::shared_ptr被过度使用了。它使用起来非常舒适,它给你的幻觉是你不必考虑所有权问题。但这不是全局。我完全同意Sean Parent“共享指针与全局变量一样好。”共享指针也会引入非常困难的所有权问题等。

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

Sean Parent关于如何避免/减少指针使用的有趣谈话是:

希望这有帮助。

答案 3 :(得分:0)

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

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

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

答案 4 :(得分:0)

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

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

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

如果现有代码与原始指针一起正常工作,为什么要花时间重写它,并且在使用版本将其转换为智能指针时冒险添加错误?

不要重构代码,这很好,因为新代码更符合现代编程标准。这些编程标准本身并不存在,但是为了更容易使用某些代码,所以不要进行重构,这将花费你更多的时间,而不是将来为你节省的时间。

这意味着:如果它将花费你更多的时间来检查,哪些指针可以安全地转换为智能指针,哪些不能和捕获错误,你的重构可能已经引入,而不是你将由于重构,能够节省未来的维护工作,然后根本不进行重构,让它保持不变。

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