智能指针的效率如何?

时间:2015-05-29 11:10:36

标签: c++ pointers c++11 std

我知道,std::shared_ptr使用引用计数,因此它具有复制和移动语义,另一方面std::unique_ptr(因此名称唯一)仅具有移动语义,因此尝试复制它是编译错误。

但是,对我而言,这个交易有多大不太清楚。在大多数情况下,我可以简单地使用std::shared_ptr而不是std::unique_ptr,或者我应该尽可能使用std::unique_ptr,因为它不会更有效率,因为它不必采取照顾参考计数?

另外,我知道智能指针在处理时非常有用,例如异常安全性,但它们是否通常取代传统的T*指针? 在可能的情况下使用智能指针而不是传统的T*指针是一种很好的编程习惯吗?

5 个答案:

答案 0 :(得分:5)

经验法则是:

  1. 如果可以,可以直接使用基于堆栈的对象,也可以使用引用而不是使用指针。
  2. 否则,如果您不必处理共享所有权(通常不要使用unique_ptr) - 它不仅更快,而且更安全(没有循环引用)。
  3. 否则,如果您确实拥有共享所有权,请使用shared_ptr
  4. 在某些情况下,原始指针在没有所有权时也可以 - 例如作为函数的输入参数:

    void draw (const shape* sh) {
        sh->draw();
    }
    
    ...
    std::unique_ptr<shape> ptr(new triangle);
    draw(ptr.get());
    

答案 1 :(得分:3)

shared_ptr的问题是,afaik,引用计数是一个原子函数,这意味着它不仅计算引用,还具有锁定功能以确保函数是原子的。所以在这一点上,是的,当你只需要移动功能时,unique_ptr更好用。

就个人而言,我不使用shared_ptr很多,大多数普通指针都足够了。 Imho智能指针只会鼓励在内存管理方面变得懒散。我参与的项目中,智能指针在退出程序时只会导致竞争条件,因为没有人知道破坏的顺序,而这些指针引用了彼此。对于我自己,我只使用它们,如果我的一个lib指向外部,当它们被删除(或以何种顺序)时它是无关紧要的。

答案 2 :(得分:1)

您应该尽可能选择值rootComponent.anyPublicFunction(val); class Shipment < ActiveRecord::Base belongs_to :user has_many :vehicles, dependent: :destroy validates :origin_id, :dest_id, :presence => true attr_accessible :origin_id, :dest_id belongs_to :origin, :class_name => 'Location', :foreign_key => 'origin_id' belongs_to :destination, :class_name =>'Location', :foreign_key => 'dest_id' end std::unique_ptr,但不是出于性能原因。是的,当涉及std::unique_ptr时会有一些开销,因为它们在某种形式的原子计数器中使用,但对于大多数应用程序来说这可以忽略不计。

使用std::shared_ptr的主要原因是唯一性语义 - 当您(或其他人)读取代码时,对象的生命周期和所有权非常清楚。这使得更容易推理代码并找到逻辑/性能问题。

PS:std::shared_ptr与原始指针相比没有开销,但它有一些很大的优势。

答案 3 :(得分:0)

如果传递给函数,则shared_ptr具有构造/销毁指针本身的额外成本,加上引用计数机制。

不要听任何人说要么智能指针总是要走的路,也不要听那些说原始指针总是更好的人。 有些情况下智能指针是有意义的,并且有原始指针是优选的情况。

如需更详细和全面的阅读,我建议您访问: http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/

它涵盖了你提出的所有要点,大部分内容都很容易阅读。

答案 4 :(得分:0)

shared_ptr表示资源周围的所有权规则很复杂。了解它们需要在一般情况下追踪所有shared_ptr的生命周期。

unique_ptr意味着围绕资源的所有权规则很容易。

两者都强制执行一组所有权规则,但unique_ptr的规则是简单且本地的,shared_ptr的规则是复杂且非本地的。如果你处于两种随意选择的情况,那么你就不会因为它们应得的引力而处理终身问题。

如果您有一个类似指针的资源,其生命周期应该简单地控制,或者甚至在某个具有复杂逻辑的中心位置(类型),请使用unique_ptr。原始指针的成本很低,它添加(强制执行)文档,这是指向此资源的“拥有”指针。

如果必须拥有一个资源,其生命周期是一堆其他对象的生命周期的并集,所有这些对象的生命周期都不相关,则可以考虑shared_ptr。如果你的情况如此复杂以至于可能形成一个循环,那么天真的shared_ptr使用不再是一个实用的选择。

shared_ptrweak_ptr也可以用作分布式生命周期通知系统,其中中心位置存储(主要是唯一的)shared_ptr,客户端存储weak_ptr 。从shared_ptr创建本地(非存储)weak_ptr以检查目标资源是否仍然存在,然后操纵资源,然后丢弃本地shared_ptr。这里的目标是(以非语言强制方式)使用弱共享的unique_ptr,因此关于生命的推理仅比unique_ptr情况稍微强一些。

shared_ptr基本上从不“解决”终身问题而不证明它会解决你的终身问题。它可以使该证明的某些部分更容易。