有人可以解释 shared_ptr 和 unique_ptr 之间的区别吗?
4 回答
这两个类都是智能指针,这意味着它们会自动(在大多数情况下)在无法再引用该对象时释放它们指向的对象。两者的区别在于每种类型有多少个不同的指针可以引用一个资源。
使用时unique_ptr
,最多可以有一个unique_ptr
指向任一资源。当它unique_ptr
被销毁时,资源会自动回收。因为任何资源只能有一个unique_ptr
,所以任何复制 a 的尝试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
使用引用计数来跟踪有多少指针引用了资源,因此您需要注意不要引入任何引用循环。
简而言之:
unique_ptr
当您想要一个指向在该单个指针被销毁时将被回收的对象的单个指针时使用。shared_ptr
当您想要多个指向同一资源的指针时使用。
希望这可以帮助!
unique_ptr
如果您在某处只有一个消费者拥有唯一(因此“唯一”)责任的动态对象,那么它是首选的轻量级智能指针——也许是一个需要维护一些动态分配的对象的包装类。unique_ptr
开销很小。它不可复制,但可移动。它的类型是template <typename D, typename Deleter> class unique_ptr;
,所以它取决于两个模板参数。
unique_ptr
这也是auto_ptr
旧 C++ 中想要的,但由于该语言的限制而不能。
shared_ptr
另一方面是一种非常不同的动物。明显的区别在于,您可以让许多消费者共同负责一个动态对象(因此是“共享的”),并且只有在所有共享指针都消失时,该对象才会被销毁。此外,您可以观察弱指针,如果它们遵循的共享指针消失了,它们会智能地得到通知。
在内部,shared_ptr
还有很多事情要做:有一个引用计数,它会自动更新以允许在并发代码中使用。此外,还有大量的分配,一个用于内部簿记“引用控制块”,另一个(通常)用于实际的成员对象。
但是还有另一个很大的区别:共享指针类型总是 template <typename T> class shared_ptr;
,尽管您可以使用自定义删除器和自定义分配器对其进行初始化。删除器和分配器使用类型擦除和虚函数分派进行跟踪,这增加了类的内部权重,但具有巨大的优势,即不同类型的共享指针T
都是兼容的,无论删除和分配细节如何。从而真正表达了“责任共担T
”的理念,又不给消费者带来太多的细节负担!
两者shared_ptr
和unique_ptr
都设计为按值传递(对唯一指针有明显的可移动性要求)。两者都不应该让您担心开销,因为它们的功能确实令人震惊,但是如果您有选择,请选择unique_ptr
,并且仅shared_ptr
在您确实需要分担责任时使用。
unique_ptr
是一个独占对象的智能指针。
shared_ptr
是共享所有权的智能指针。它既是 又copyable
是movable
。多个智能指针实例可以拥有相同的资源。一旦拥有该资源的最后一个智能指针超出范围,该资源就会被释放。
将指针包装在 a 中时,unique_ptr
您不能拥有多个unique_ptr
. 它shared_ptr
拥有一个引用计数器,用于计算存储指针的副本数。每次shared_ptr
复制 a 时,此计数器都会递增。每次 ashared_ptr
被破坏时,该计数器都会递减。当此计数器达到 0 时,存储的对象将被销毁。