【问题标题】:Differences between unique_ptr and shared_ptr [duplicate]unique_ptr 和 shared_ptr 之间的区别 [重复]
【发布时间】:2011-10-16 03:30:38
【问题描述】:

可能的重复:
pimpl: shared_ptr or unique_ptr
smart pointers (boost) explained

有人能解释一下 shared_ptr 和 unique_ptr 之间的区别吗?

【问题讨论】:

标签: c++ pointers c++11 shared-ptr unique-ptr


【解决方案1】:

这两个类都是智能指针,这意味着它们会自动(在大多数情况下)在无法再引用该对象时释放它们指向的对象。两者的区别在于每种类型有多少个不同的指针可以引用一个资源。

当使用unique_ptr 时,最多可以有一个unique_ptr 指向任一资源。当unique_ptr 被销毁时,资源会自动回收。因为任何资源只能有一个unique_ptr,所以任何复制unique_ptr 的尝试都会导致编译时错误。例如,这段代码是非法的:

unique_ptr<T> myPtr(new T);       // Okay
unique_ptr<T> myOtherPtr = myPtr; // Error: Can't copy unique_ptr

不过,unique_ptr 可以使用新的移动语义移动

unique_ptr<T> myPtr(new T);                  // Okay
unique_ptr<T> myOtherPtr = std::move(myPtr); // Okay, resource now stored in myOtherPtr

同样,你可以这样做:

unique_ptr<T> MyFunction() {
    unique_ptr<T> myPtr(/* ... */);

    /* ... */

    return myPtr;
}

这个习惯用法的意思是“我正在向您返回一个托管资源。如果您没有明确捕获返回值,那么该资源将被清理。如果您这样做了,那么您现在拥有该资源的独占所有权。 "这样,您可以将unique_ptr 视为auto_ptr 的更安全、更好的替代品。

shared_ptr,另一方面,允许多个指针指向一个给定的资源。当资源的最后一个shared_ptr 被销毁时,该资源将被释放。例如,这段代码是完全合法的:

shared_ptr<T> myPtr(new T);       // Okay
shared_ptr<T> myOtherPtr = myPtr; // Sure!  Now have two pointers to the resource.

在内部,shared_ptr 使用reference counting 来跟踪有多少指针引用了资源,因此您需要注意不要引入任何引用循环。

简而言之:

  1. 如果您想要一个指向在该单个指针被销毁时将被回收的对象的单个指针,请使用 unique_ptr
  2. 如果您需要多个指向同一资源的指针,请使用 shared_ptr

希望这会有所帮助!

【讨论】:

  • unique_ptr 在删除器方面可能有点问题。 shared_ptr 总是会做“正确的事”,只要它是用 make_shared 创建的。但是如果你创建了一个unique_ptr&lt;Derived&gt;,然后将其转换为unique_ptr&lt;Base&gt;,并且如果Derived 是虚拟的而Base 不是,那么指针将通过错误的类型被删除并且可能存在未定义的行为。这可以通过unique_ptr&lt;T, DeleterType&gt; 中的适当删除器类型来修复,但默认使用风险更高的版本,因为它更有效。
  • @AaronMcDaid 默认情况下,unique_ptr 的行为类似于您不能忘记指向delete 的原始指针:如果您忘记将 dtor 设为虚拟,它就在您身上。
  • 我更喜欢使用make_unique 而不是new。它更清洁、更安全、更高效。
  • @templatetypedef 你能举例说明如何将MyFunction() 的返回值捕获到调用者范围内的另一个指针中吗?
  • 这么好的答案
【解决方案2】:

unique_ptr 是选择的轻量级智能指针,如果您在某处只有一个动态对象 one 消费者对其负有唯一(因此“独特”)责任——也许是一个包装类需要维护一些动态分配的对象。 unique_ptr 的开销很小。它不可复制,但可移动。它的typetemplate &lt;typename D, typename Deleter&gt; class unique_ptr;,所以它依赖于两个模板参数。

unique_ptr 也是 auto_ptr 想要在旧 C++ 中使用的,但由于该语言的限制而无法使用。

另一方面,shared_ptr 是一种非常不同的动物。明显的区别是,您可以让许多消费者对动态对象(因此是“共享的”)分担责任,并且只有在所有共享指针都消失时,该对象才会被销毁。此外,您还可以观察 弱指针,如果它们所关注的共享指针消失了,它将智能地得到通知。

在内部,shared_ptr 有很多事情要做:有一个引用计数,它会自动更新以允许在并发代码中使用。此外,还有大量分配正在进行,一个用于内部簿记“引用控制块”,另一个(通常)用于实际的成员对象。

但是还有一个很大的区别:共享指针类型是alwaystemplate &lt;typename T&gt; class shared_ptr;,尽管你可以使用自定义删除器来初始化它并且使用自定义分配器。删除器和分配器使用类型擦除和虚函数分派进行跟踪,这增加了类的内部权重,但具有巨大的优势,即T 类型的不同类型的共享指针都兼容,无论删除和分配细节。因此,他们真正表达了“为T承担责任”的概念,而不会给消费者带来任何细节负担!

shared_ptrunique_ptr 都设计为按值传递(对唯一指针有明显的可移动性要求)。两者都不应该让您担心开销,因为它们的功能确实令人震惊,但是如果您可以选择,请首选unique_ptr,并且仅在您确实需要共同承担责任时才使用shared_ptr

【讨论】:

  • “设计为按值传递” ??
  • 投了赞成票,因为我对 shared_ptr 的引用计数器实际上可能在哪里感到困惑(毕竟,多个 shared_ptr 和一个共享资源意味着一个共享引用计数器太正确了?所以不能包含计数器在 shared_ptr 中)。这是我见过的第一个回答我的问题的 shared_ptr 解释;分配了一个单独的参考计数器。据推测,它在计数 0->1 时分配一次,在计数 1->0 时释放一次,就像受控资源一样。
  • 复制不了怎么传值?
  • @splinter123:通过移动它!
  • @Farzan:是的,准确地说。您可以使用临时函数(根据定义无法访问该函数)调用该函数,或者您需要将 std::move(x) 作为参数传递,这意味着 x 将被移出。
【解决方案3】:

unique_ptr
是一个独占对象的智能指针。

shared_ptr
是共享所有权的智能指针。它是copyablemovable。多个智能指针实例可以拥有相同的资源。一旦拥有该资源的最后一个智能指针超出范围,该资源就会被释放。

【讨论】:

    【解决方案4】:

    unique_ptr 中包装指针时,您不能拥有unique_ptr 的多个副本。 shared_ptr 拥有一个引用计数器,用于计算存储指针的副本数。每次复制 shared_ptr 时,此计数器都会递增。每次 shared_ptr 被破坏时,该计数器就会递减。当这个计数器达到 0 时,存储的对象就被销毁了。

    【讨论】:

    • 计数器是一个实现细节。重要的是 shared_ptr 的“家族”是彼此的副本,能够确定家族的最后一个成员何时被破坏。
    猜你喜欢
    • 2013-08-24
    • 2014-10-12
    • 1970-01-01
    • 1970-01-01
    • 2013-07-21
    • 2014-08-16
    • 2011-04-08
    • 2012-11-24
    • 2013-06-05
    相关资源
    最近更新 更多