unique_ptr和shared_ptr的区别

< p > 可能的重复: < br > Pimpl: shared_ptr或unique_ptr < br > 智能指针(增强)解释 < / p >

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

274268 次浏览

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

< p > unique_ptr < br >

< p > 要查看 < br > 是共享所有权的智能指针。它是copyablemovable。多个智能指针实例可以拥有相同的资源。一旦拥有该资源的最后一个智能指针超出作用域,该资源将被释放

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

当使用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

然而,使用新的move语义,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_ptrauto_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使用引用计数来跟踪有多少指针引用了一个资源,所以你需要小心不要引入任何引用循环。

简而言之:

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

希望这能有所帮助!

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

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

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

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

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

shared_ptrunique_ptr都被设计为按值传递(对唯一指针有明显的可移动性要求)。它们都不应该让你担心开销,因为它们的功能确实令人震惊,但如果你有选择,更喜欢unique_ptr,只有在你确实需要分担责任时才使用shared_ptr