智能指针的效率如何?

How efficient smart pointers are?

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

但是,我不太清楚这有多大意义。在大多数情况下,我可以简单地使用 std::shared_ptr 而不是 std::unique_ptr,还是应该尽可能使用 std::unique_ptr,因为它不需要处理引用计数,因此效率更高?

此外,我知道智能指针在处理异常安全等问题时很有用,但它们是否可以普遍取代传统的 T* 指针? 尽可能使用智能指针而不是传统的 T* 指针是一种好的编程习惯吗?

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

就个人而言,我不经常使用 shared_ptr,大多数普通指针就足够了。恕我直言,智能指针只会鼓励在内存管理中变得懒惰。我在一些项目中,智能指针只会在退出程序时导致竞争条件,因为没有人知道销毁的顺序,而且这些指针相互引用。对于我自己,我只在我的一个库将指针指向外部时才使用它们,当它们被删除时(或以何种顺序)它是无关紧要的。

A shared_ptr 具有指针本身的 construction/destruction 的额外成本,如果传递给函数,加上引用计数机制。

不要听任何人说智能指针总是可行的,也不要听那些说原始指针总是更好的人。 有些情况下智能指针有意义,有些情况下原始指针更可取。

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

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

经验法则是:

  1. 如果可以,直接或通过引用使用基于堆栈的对象,而不是使用指针。
  2. 否则,如果您不必处理共享所有权(通常不需要),请使用 unique_ptr - 它不仅更快,而且更安全(无循环引用)。
  3. 否则,如果您确实拥有共享所有权,请使用 shared_ptr

原始指针在某些情况下是可以的,当它们不带有所有权时——例如作为函数的输入参数:

void draw (const shape* sh) {
    sh->draw();
}

...
std::unique_ptr<shape> ptr(new triangle);
draw(ptr.get());

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

unique_ptr 意味着围绕资源的所有权规则非常简单。

两者都执行一套所有权规则,但 unique_ptr 的规则简单且本地化,shared_ptr 的规则复杂且非本地化。如果你处在随便在两者之间做出选择的情况下,那么你就不会以他们应得的重力来对待生活问题。

如果你有一个类似指针的资源,它的生命周期应该被简单地控制,或者甚至在一些中心位置(类型方面)周围有复杂的逻辑,使用 unique_ptr。原始指针的成本是最小的,并且它添加(强制)文档表明这是指向此资源的 "owning" 指针。

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

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

shared_ptr 基本上 永远不会 "solves" 没有你证明它会解决你一生的问题。它可以使该证明的某些部分稍微容易一些。

您应该尽可能选择值而不是 std::unique_ptr,选择 std::unique_ptr 而不是 std::shared_ptr,但不是出于性能原因。是的,当涉及到 std::shared_ptr 时会有一些开销,因为它们在某种形式的原子计数器中使用,但这对于大多数应用程序来说可以忽略不计。

使用 std::unique_ptr 的主要原因是唯一性语义 - 当您(或其他人)阅读代码时,您会非常清楚对象的生命周期和所有权。这使得推理代码和发现 logical/performance 个问题变得更加容易。

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