简短版本:
在现代C ++中使用非智能指针是否有任何可接受的原因?
长版:
我们有一个包含很多旧C ++代码的庞大产品,现在我们正试图将它重构为现代C ++时代。除了所有旧式代码之外,还有大量的指针传递(主要是使用SAL注释来提供一些安全感),我想知道是否应该将它们全部更改为智能指针,或者可能将其中的一些保留为智能指针。 ?
试图转换其中的一些代码,我最终得到了一个代码,这个代码可以说明使用智能指针。
所以问题是:是否存在使用智能指针的问题? 换句话说:这些天非智能指针是否有任何可接受的场景?
答案 0 :(得分:5)
智能指针(unique_ptr
和shared_ptr
)应该是OWNING指针(即负责销毁对象)。使用它们的底线是,new
创建的任何对象都应该尽快推送到unique_ptr
,以防止内存泄漏。之后,unique_ptr
最终应该被移动:
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 ++”是> = c ++ 11
长期的答案并非总是如此,尝试重组大型项目几乎总是很难。我们思考问题的方式受到我们解决问题的工具的限制。有很多情况下进行这样的重构时,使用指针比尝试将基本逻辑重新表达为类和智能指针友好更简单。我认为这不是智能指针过度使用的情况,而是在使用类时更多的情况。 YMMV; - )
答案 4 :(得分:0)
当然在现代C ++中有原始指针的用例:
当然这些是非常罕见的情况,到目前为止,指针智能指针的大多数用例应该适用于新代码,但是:
如果现有代码与原始指针一起正常工作,为什么要花时间重写它,并且在使用版本将其转换为智能指针时冒险添加错误?
不要重构代码,这很好,因为新代码更符合现代编程标准。这些编程标准本身并不存在,但是为了更容易使用某些代码,所以不要进行重构,这将花费你更多的时间,而不是将来为你节省的时间。
这意味着:如果它将花费你更多的时间来检查,哪些指针可以安全地转换为智能指针,哪些不能和捕获错误,你的重构可能已经引入,而不是你将由于重构,能够节省未来的维护工作,然后根本不进行重构,让它保持不变。
如果重构将比仅为代码库的某些部分节省更多时间,那么请考虑仅重构代码库的那些部分。