15.6 — std::shared_ptr

Unlike std::unique_ptr, which is designed to singly own and manage a resource, std::shared_ptr is meant to solve the case where you need multiple smart pointers co-owning a resource.

This means that it is fine to have multiple std::shared_ptr pointing to the same resource. Internally, std::shared_ptr keeps track of how many std::shared_ptr are sharing the resource. As long as at least one std::shared_ptr is pointing to the resource, the resource will not be deallocated, even if individual std::shared_ptr are destroyed. As soon as the last std::shared_ptr managing the resource goes out of scope (or is reassigned to point at something else), the resource will be deallocated.

Like std::unique_ptr, std::shared_ptr lives in the <memory> header.

This prints:

Resource acquired
Killing one shared pointer
Killing another shared pointer
Resource destroyed

In the above code, we create a dynamic Resource object, and set a std::shared_ptr named ptr1 to manage it. Inside the nested block, we use copy initialization (which is allowed with std::shared_ptr, since the resource can be shared) to create a second std::shared_ptr (ptr2) that points to the same Resource. When ptr2 goes out of scope, the Resource is not deallocated, because ptr1 is still pointing at the Resource. When ptr1 goes out of scope, ptr1 notices there are no more std::shared_ptr managing the Resource, so it deallocates the Resource.

Note that we created a second shared pointer from the first shared pointer (using copy initialization). This is important. Consider the following similar program:

This program prints:

Resource acquired
Killing one shared pointer
Resource destroyed
Killing another shared pointer
Resource destroyed

and then crashes (at least on the author’s machine).

The difference here is that we created two std::shared_ptr independently from each other. As a consequence, even though they’re both pointing to the same Resource, they aren’t aware of each other. When ptr2 goes out of scope, it thinks it’s the only owner of the Resource, and deallocates it. When ptr1 later goes out of the scope, it thinks the same thing, and tries to delete the Resource again. Then bad things happen.

Fortunately, this is easily avoided by using copy assignment or copy initialization when you need multiple shared pointers pointing to the same Resource.

Rule: Always make a copy of an existing std::shared_ptr if you need more than one std::shared_ptr pointing to the same resource.


Much like std::make_unique() can be used to create a std::unique_ptr in C++14, std::make_shared() can (and should) be used to make a std::shared_ptr. std::make_shared() is available in C++11.

Here’s our original example, using std::make_shared():

The reasons for using std::make_shared() are the same as std::make_unique() -- std::make_shared() is simpler and safer (there’s no way to directly create two std::shared_ptr pointing to the same resource using this method). However, std::make_shared() is also more performant than not using it. The reasons for this lie in the way that std::shared_ptr keeps track of how many pointers are pointing at a given resource.

Digging into std::shared_ptr

Unlike std::unique_ptr, which uses a single pointer internally, std::shared_ptr uses two pointers internally. One pointer points at the resource being managed. The other points at a “control block”, which is a dynamically allocated object that tracks of a bunch of stuff, including how many std::shared_ptr are pointing at the resource. When a std::shared_ptr is created via a std::shared_ptr constructor, the memory for the managed object (which is usually passed in) and control block (which the constructor creates) are allocated separately. However, when using std::make_shared(), this can be optimized into a single memory allocation, which leads to better performance.

This also explains why independently creating two std::shared_ptr pointed to the same resource gets us into trouble. Each std::shared_ptr will have one pointer pointing at the resource. However, each std::shared_ptr will independently allocate its own control block, which will indicate that it is the only pointer owning that resource. Thus, when that std::shared_ptr goes out of scope, it will deallocate the resource, not realizing there are other std::shared_ptr also trying to manage that resource.

However, when a std::shared_ptr is cloned using copy assignment, the data in the control block can be appropriately updated to indicate that there are now additional std::shared_ptr co-managing the resource.

Shared pointers can be created from unique pointers

A std::unique_ptr can be converted into a std::shared_ptr via a special std::shared_ptr constructor that accepts a std::unique_ptr r-value. The contents of the std::unique_ptr will be moved to the std::shared_ptr.

However, std::shared_ptr can not be safely converted to a std::unique_ptr. This means that if you’re creating a function that is going to return a smart pointer, you’re better off returning a std::unique_ptr and assigning it to a std::shared_ptr if and when that’s appropriate.

The perils of std::shared_ptr

std::shared_ptr has some of the same challenges as std::unique_ptr -- if the std::shared_ptr is not properly disposed of (either because it was dynamically allocated and never deleted, or it was part of an object that was dynamically allocated and never deleted) then the resource it is managing won’t be deallocated either. With std::unique_ptr, you only have to worry about one smart pointer being properly disposed of. With std::shared_ptr, you have to worry about them all. If any of the std::shared_ptr managing a resource are not properly destroyed, the resource will not be deallocated properly.

std::shared_ptr and arrays

In C++14 and earlier, std::shared_ptr does not have proper support for managing arrays, and should not be used to manage a C-style array. As of C++17, std::shared_ptr does have support for arrays. However, as of C++17, std::make_shared is still lacking proper support for arrays, and should not be used to create shared arrays. This will likely be addressed in C++20.


std::shared_ptr is designed for the case where you need multiple smart pointers co-managing the same resource. The resource will be deallocated when the last std::shared_ptr managing the resource is destroyed.

15.7 -- Circular dependency issues with std::shared_ptr, and std::weak_ptr
15.5 -- std::unique_ptr

30 comments to 15.6 — std::shared_ptr

  • Alexandra


    I have a question related to std::shared_ptr.

    Can you tell me please why I can still call print() method after I destroyed the Resource object by using reset()?

    #include <iostream>
    #include <memory>

    class Resource
        Resource() { std::cout << "Resource acquired\n"; }
        ~Resource() { std::cout << "Resource destroyed\n"; }
        void print() { std::cout << "Yey!!!!\n"; }

    int main()
        auto ptr1 = std::make_shared<Resource>();


        return 0;

    The output of executing this is:

    Resource acquired
    Resource destroyed

    Thank you!

    • This is undefined behavior.
      Why it's probably working for you: The functions aren't bound to an object, ie. they're the same for every instance of `Resource` and don't access any members. The member functions don't die with the object, they live as long as the program lives. Since they're independent of the object, you can call them even if there is not valid object.
      Again, it's UB, don't do it.

  • Abhijit

    You mentioned
    "In C++14 and earlier, std::shared_ptr does not have proper support for managing arrays, and should not be used to manage a C-style array"
    If we still have to use, what is the alternative?

  • is using vector/string also is better than to using shared_ptr for dynamic arrays and strings ?, also vector/string do not have support for move semantics if i understand correctly, thus in case dealing with r values a vector/string won't steal rather make a deep copy which is inefficient, how can i choose which is better to use in array context ? i mean if an array is going to be shared then i should use shared_ptr, if not then vector ?

  • Jon

    To make sure I've got it, say you have 5 shared_ptr's all co-managing the same resource and you want to create a 6th, it doesn't matter which of the original 5 you clone using copy assignment because they all share the same control block?

    Or do they still all have their own control blocks, but with identical data in each?

  • hailinh0708

    In the topic, you said:
    "As of C++17, std::share_ptr does have support for arrays."
    std::share_ptr should be std::shared_ptr.

  • Azad

    Hello Alex,

    1) Can you pls show a best code for shared_ptr implementation ?

    2) why incrementing reference counter in default constructor here? Default means shared_Ptr still doesn’t point to anything ? Is it right implementation?

    SP() : pData(0), reference(0)

    But here no increment here:

    Which one is right?

    3) why reference counter is decremented and deleted data in assignment operator before incrementing? ? Any example?

    Shared_ptr<T> p1 (new T())

    Shared_ptr<T> p2 = p1  // here counter should be increased to 2. When it can be decremented?//

    Thanks in advance.

  • Azad

    Hello Alex,

    How to implement shared_ptr? Any help? Thanks

  • DC

    i am confused about smart pointers in the context of passing by reference/address? Could you please explain this? Should we be using smart pointers when passing by reference/address? what are the advantages?

    • Alex

      I just updated the lesson on std::unique_ptr to help address this. While you can pass smart pointers by address or reference, instead it's better to pass the resource being managed (rather than the smart pointer itself) by pointer or reference. The called function shouldn't need to know or care how the callee is managing the lifetime of the resource.

  • Mohsen

    Hi Alex. Thanks in advance for replying all of questions.
    Here's another one :-) .
    I always use "using namespace std" on top to avoid typing std::... .
    In above example, when i used make_shared, my text editor put a red line under cout and says "cout is ambiguous". although it does compile and run properly that, was strange for me.
    When i added std:: before "cout", red line disappeared.
    Can you explain what was that?

    • Alex

      You were getting some sort of naming collision on the name "cout". When you added the std:: prefix, the compiler could tell that you meant std::cout as opposed to some other cout that you'd apparently defined somewhere.

  • Sheng

    Hi Alex,
    On line "Note that we created a second shared pointer from the first shared pointer using copy assignment. This is important. Consider the following similar program:"
    right before the second code block, do you mean copy constructor instead?


  • Bobix

    Hi Alex,
      I have some confusion regarding the 2 pointers(1. Pointer pointing to the actual managed object, 2. Pointer pointing to the control block) held by the std::shared_ptr. While referring to the , i could see the below description under the 'Implementation notes' section
    In a typical implementation, std::shared_ptr holds only two pointers:
       1. the stored pointer (one returned by get());
       2. a pointer to control block.
    The control block is a dynamically-allocated object that holds:
       1. either a pointer to the managed object or the managed object itself;
       2. the deleter (type-erased);
       3. the allocator (type-erased);
       4. the number of shared_ptrs that own the managed object;
       5. the number of weak_ptrs that refer to the managed object.

    And further down it is mentioned that 'The pointer held by the shared_ptr directly is the one returned by get(), while the pointer/object held by the control block is the one that will be deleted when the number of shared owners reaches zero. These pointers are not necessarily equal.'

    My confusion is regarding the pointer inside the control block. Why is it needed if the std::shared_ptr object already holds 2 pointers (one to point to the actual managed object and other to point to the control block). Basically i am confused about the memory layout of the shared_ptr.

    It would be great if you could help me out here a bit.

  • john

    I think smart pointers are another great example of how abstraction makes our life easier by hiding the "dirty details" that goes on behind the scenes. Your introduction to the OOP in chapter 8 really gave me a lot to think about :)

  • john

    Is shared pointer somehow connected to the reference counting? I've only heared the term before but don't know exactly what it is.

    • Alex

      Yes. Reference counting is the technique of "keeping a numeric counter of how many references there are to some object". Every time a new reference is set to the object, you increment the counter. Every time a reference is cleared, you decrement the counter. When the counter reaches 0, you know that nobody is using the object any more.

  • Maxpro

    think line 13 on 1st and 3rd code example have typo saying unique_ptr instead of shared.

    thanks for the tutorials, please consider doing ones covering the basics of futures and promises.

Leave a Comment

Put all code inside code tags: [code]your code here[/code]