【发布时间】: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
可能的重复:
pimpl: shared_ptr or unique_ptr
smart pointers (boost) explained
有人能解释一下 shared_ptr 和 unique_ptr 之间的区别吗?
【问题讨论】:
标签: c++ pointers c++11 shared-ptr 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 可以使用新的移动语义移动:
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 来跟踪有多少指针引用了资源,因此您需要注意不要引入任何引用循环。
简而言之:
unique_ptr。shared_ptr。希望这会有所帮助!
【讨论】:
unique_ptr 在删除器方面可能有点问题。 shared_ptr 总是会做“正确的事”,只要它是用 make_shared 创建的。但是如果你创建了一个unique_ptr<Derived>,然后将其转换为unique_ptr<Base>,并且如果Derived 是虚拟的而Base 不是,那么指针将通过错误的类型被删除并且可能存在未定义的行为。这可以通过unique_ptr<T, DeleterType> 中的适当删除器类型来修复,但默认使用风险更高的版本,因为它更有效。
unique_ptr 的行为类似于您不能忘记指向delete 的原始指针:如果您忘记将 dtor 设为虚拟,它就在您身上。
make_unique 而不是new。它更清洁、更安全、更高效。
MyFunction() 的返回值捕获到调用者范围内的另一个指针中吗?
unique_ptr 是选择的轻量级智能指针,如果您在某处只有一个动态对象 one 消费者对其负有唯一(因此“独特”)责任——也许是一个包装类需要维护一些动态分配的对象。 unique_ptr 的开销很小。它不可复制,但可移动。它的type是template <typename D, typename Deleter> class unique_ptr;,所以它依赖于两个模板参数。
unique_ptr 也是 auto_ptr 想要在旧 C++ 中使用的,但由于该语言的限制而无法使用。
另一方面,shared_ptr 是一种非常不同的动物。明显的区别是,您可以让许多消费者对动态对象(因此是“共享的”)分担责任,并且只有在所有共享指针都消失时,该对象才会被销毁。此外,您还可以观察 弱指针,如果它们所关注的共享指针消失了,它将智能地得到通知。
在内部,shared_ptr 有很多事情要做:有一个引用计数,它会自动更新以允许在并发代码中使用。此外,还有大量分配正在进行,一个用于内部簿记“引用控制块”,另一个(通常)用于实际的成员对象。
但是还有一个很大的区别:共享指针类型是alwaystemplate <typename T> class shared_ptr;,尽管你可以使用自定义删除器来初始化它并且使用自定义分配器。删除器和分配器使用类型擦除和虚函数分派进行跟踪,这增加了类的内部权重,但具有巨大的优势,即T 类型的不同类型的共享指针都兼容,无论删除和分配细节。因此,他们真正表达了“为T承担责任”的概念,而不会给消费者带来任何细节负担!
shared_ptr 和unique_ptr 都设计为按值传递(对唯一指针有明显的可移动性要求)。两者都不应该让您担心开销,因为它们的功能确实令人震惊,但是如果您可以选择,请首选unique_ptr,并且仅在您确实需要共同承担责任时才使用shared_ptr。
【讨论】:
std::move(x) 作为参数传递,这意味着 x 将被移出。
unique_ptr
是一个独占对象的智能指针。
shared_ptr
是共享所有权的智能指针。它是copyable 和movable。多个智能指针实例可以拥有相同的资源。一旦拥有该资源的最后一个智能指针超出范围,该资源就会被释放。
【讨论】:
在unique_ptr 中包装指针时,您不能拥有unique_ptr 的多个副本。 shared_ptr 拥有一个引用计数器,用于计算存储指针的副本数。每次复制 shared_ptr 时,此计数器都会递增。每次 shared_ptr 被破坏时,该计数器就会递减。当这个计数器达到 0 时,存储的对象就被销毁了。
【讨论】:
shared_ptr 的“家族”是彼此的副本,能够确定家族的最后一个成员何时被破坏。