可能的重复: Pimpl: shared_ptr或unique_ptr 智能指针(增强)解释

有人能解释shared_ptr和unique_ptr之间的差异吗?


当前回答

当在unique_ptr中包装一个指针时,不能有unique_ptr的多个副本。shared_ptr包含一个引用计数器,用于计算所存储指针的副本数量。每次复制shared_ptr时,这个计数器都会增加。每次shared_ptr被销毁时,这个计数器都会递减。当该计数器达到0时,存储的对象将被销毁。

其他回答

当在unique_ptr中包装一个指针时,不能有unique_ptr的多个副本。shared_ptr包含一个引用计数器,用于计算所存储指针的副本数量。每次复制shared_ptr时,这个计数器都会增加。每次shared_ptr被销毁时,这个计数器都会递减。当该计数器达到0时,存储的对象将被销毁。

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

要查看 是共享所有权的智能指针。它既可复制又可移动。多个智能指针实例可以拥有相同的资源。一旦拥有该资源的最后一个智能指针超出作用域,该资源将被释放。

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

当使用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可以使用新的move语义进行移动:

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使用引用计数来跟踪有多少指针引用了一个资源,因此您需要注意不要引入任何引用循环。

简而言之:

当您想要一个指向对象的单指针,并且该对象的单指针被销毁时将被回收时,请使用unique_ptr。 当你想要多个指向同一个资源的指针时,使用shared_ptr。

Unique_ptr是轻量级智能指针的选择,如果您只是在某个地方有一个动态对象,其中一个消费者只有一个责任(因此是“唯一的”)——可能是一个包装器类,需要维护一些动态分配的对象。Unique_ptr的开销很小。它不是可复制的,而是可移动的。它的类型是template <typename D, typename Deleter>类unique_ptr;,因此它依赖于两个模板参数。

unique_ptr也是auto_ptr想要在旧c++中实现的功能,但由于该语言的局限性而无法实现。

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

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

But there's another big difference: The shared pointers type is always template <typename T> class shared_ptr;, and this is despite the fact that you can initialize it with custom deleters and with custom allocators. The deleter and allocator are tracked using type erasure and virtual function dispatch, which adds to the internal weight of the class, but has the enormous advantage that different sorts of shared pointers of type T are all compatible, no matter the deletion and allocation details. Thus they truly express the concept of "shared responsibility for T" without burdening the consumer with the details!

shared_ptr和unique_ptr都被设计为按值传递(对唯一指针有明显的可移动性要求)。这两种方法都不应该让您担心开销,因为它们的功能确实令人震惊,但是如果可以选择,请使用unique_ptr,如果确实需要共享责任,则只使用shared_ptr。