Differences between unique_ptr and shared_ptr

252,901

Solution 1

Both of these classes are smart pointers, which means that they automatically (in most cases) will deallocate the object that they point at when that object can no longer be referenced. The difference between the two is how many different pointers of each type can refer to a resource.

When using unique_ptr, there can be at most one unique_ptr pointing at any one resource. When that unique_ptr is destroyed, the resource is automatically reclaimed. Because there can only be one unique_ptr to any resource, any attempt to make a copy of a unique_ptr will cause a compile-time error. For example, this code is illegal:

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

However, unique_ptr can be moved using the new move semantics:

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

Similarly, you can do something like this:

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

    /* ... */

    return myPtr;
}

This idiom means "I'm returning a managed resource to you. If you don't explicitly capture the return value, then the resource will be cleaned up. If you do, then you now have exclusive ownership of that resource." In this way, you can think of unique_ptr as a safer, better replacement for auto_ptr.

shared_ptr, on the other hand, allows for multiple pointers to point at a given resource. When the very last shared_ptr to a resource is destroyed, the resource will be deallocated. For example, this code is perfectly legal:

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

Internally, shared_ptr uses reference counting to track how many pointers refer to a resource, so you need to be careful not to introduce any reference cycles.

In short:

  1. Use unique_ptr when you want a single pointer to an object that will be reclaimed when that single pointer is destroyed.
  2. Use shared_ptr when you want multiple pointers to the same resource.

Hope this helps!

Solution 2

unique_ptr is the light-weight smart pointer of choice if you just have a dynamic object somewhere for which one consumer has sole (hence "unique") responsibility -- maybe a wrapper class that needs to maintain some dynamically allocated object. unique_ptr has very little overhead. It is not copyable, but movable. Its type is template <typename D, typename Deleter> class unique_ptr;, so it depends on two template parameters.

unique_ptr is also what auto_ptr wanted to be in the old C++ but couldn't because of that language's limitations.

shared_ptr on the other hand is a very different animal. The obvious difference is that you can have many consumers sharing responsibility for a dynamic object (hence "shared"), and the object will only be destroyed when all shared pointers have gone away. Additionally you can have observing weak pointers which will intelligently be informed if the shared pointer they're following has disappeared.

Internally, shared_ptr has a lot more going on: There is a reference count, which is updated atomically to allow the use in concurrent code. Also, there's plenty of allocation going on, one for an internal bookkeeping "reference control block", and another (often) for the actual member object.

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!

Both shared_ptr and unique_ptr are designed to be passed by value (with the obvious movability requirement for the unique pointer). Neither should make you worried about the overhead, since their power is truly astounding, but if you have a choice, prefer unique_ptr, and only use shared_ptr if you really need shared responsibility.

Solution 3

unique_ptr
is a smart pointer which owns an object exclusively.

shared_ptr
is a smart pointer for shared ownership. It is both copyable and movable. Multiple smart pointer instances can own the same resource. As soon as the last smart pointer owning the resource goes out of scope, the resource will be freed.

Solution 4

When wrapping a pointer in a unique_ptr you cannot have multiple copies of unique_ptr. The shared_ptr holds a reference counter which count the number of copies of the stored pointer. Each time a shared_ptr is copied, this counter is incremented. Each time a shared_ptr is destructed, this counter is decremented. When this counter reaches 0, then the stored object is destroyed.

Share:
252,901

Related videos on Youtube

smallB
Author by

smallB

Updated on July 08, 2022

Comments

  • smallB
    smallB almost 2 years

    Possible Duplicates:
    pimpl: shared_ptr or unique_ptr
    smart pointers (boost) explained

    Could someone explain differences between shared_ptr and unique_ptr?

  • Ajay
    Ajay over 10 years
    "designed to be passed by value" ??
  • Aaron McDaid
    Aaron McDaid almost 9 years
    unique_ptr can be a little buggy regarding deleters. shared_ptr will always do "the right thing", as long it was created with make_shared. But if you create a unique_ptr<Derived>, then convert it to unique_ptr<Base>, and if Derived is virtual and Base is not, then the pointer will be deleted through the wrong type and there can be undefined behaviour. This can be fixed with an appropriate deleter-type in the unique_ptr<T, DeleterType>, but the default is to use the riskier version because it is a little more efficient.
  • Bill Forster
    Bill Forster over 8 years
    Upvoted since I was puzzled about where the shared_ptr's reference counter could actually be (after all, multiple shared_ptrs and a single shared resource means a single shared reference counter too right? So the counter can't be contained within a shared_ptr). This is the first shared_ptr explanation that I've seen that answers my question; A separate reference counter is allocated. Presumably it's allocated once at count 0->1 and freed once at count 1->0, just like the controlled resource.
  • splinter123
    splinter123 almost 8 years
    How can you pass it by value if you cannot copy it?
  • Kerrek SB
    Kerrek SB almost 8 years
    @splinter123: By moving it!
  • curiousguy
    curiousguy almost 6 years
    @AaronMcDaid By default unique_ptr will behave like a raw pointer that you can't forget to delete: if you forget to make the dtor virtual, it's on you.
  • curiousguy
    curiousguy almost 6 years
    The counter is an implementation detail. What matters is that the "family" of shared_ptr that are copies of each other is able to determine when the last member of the family is destructed.
  • SubMachine
    SubMachine over 5 years
    I prefer using make_unique instead of new. It is cleaner, safer and more efficient.
  • Vassilis
    Vassilis over 5 years
    @templatetypedef could you give an example of how to capture the return value of your MyFunction() into another pointer in the caller's scope?
  • Farzan
    Farzan over 4 years
    @KerrekSB "you can have observing weak pointers which will intelligently be informed if the shared pointer they're following has disappeared", Could you please elaborate how?
  • Farzan
    Farzan over 4 years
    @KerrekSB "By moving it", Does it mean when passing a unique_ptr to a function by value then the caller has no access to the original unique_ptr?
  • Kerrek SB
    Kerrek SB over 4 years
    @Farzan: Yes, precisely. Either you call the function with a temporary (to which you have no access by definition), or you need to pass something like std::move(x) as an argument, which means that x is then moved-from.
  • tae ha
    tae ha about 3 years
    such a great answer
  • Mikko Rantalainen
    Mikko Rantalainen almost 3 years
    If you were to write C++ code where all your code and all your library code only used unique_ptr for all objects, you'd basically end up with Rust with uglier syntax. Borrowing could be implemented by moving unique_ptr in as function arguments and then moving the unique_ptr back during function return. If you also had threading implementation following the same rules you could have thread safety similar way as Rust has (that is, data races are not possible because safe Rust cannot race to shared data).
  • Mikko Rantalainen
    Mikko Rantalainen almost 3 years
    @Ajay: the smart pointer is passed by value, the object pointed by the smart pointer is obviously used by reference (the smart pointer).