M.6 — std::unique_ptr

At the beginning of the chapter, we discussed how use of pointers can lead to bugs and memory leaks in some situations. For example, this can happen when a function early returns, or throws an exception, and the pointer is not properly deleted.

Now that we’ve covered the fundamentals of move semantics, we can return to the topic of smart pointer classes. As a reminder, a smart pointer is a class that manages a dynamically allocated object. Although smart pointers can offer other features, the defining characteristic of a smart pointer is that it manages a dynamically allocated resource, and ensures the dynamically allocated object is properly cleaned up at the appropriate time (usually when the smart pointer goes out of scope).

Because of this, smart pointers should never be dynamically allocated themselves (otherwise, there is the risk that the smart pointer may not be properly deallocated, which means the object it owns would not be deallocated, causing a memory leak). By always allocating smart pointers on the stack (as local variables or composition members of a class), we’re guaranteed that the smart pointer will properly go out of scope when the function or object it is contained within ends, ensuring the object the smart pointer owns is properly deallocated.

C++11 standard library ships with 4 smart pointer classes: std::auto_ptr (which you shouldn’t use -- it’s being removed in C++17), std::unique_ptr, std::shared_ptr, and std::weak_ptr. std::unique_ptr is by far the most used smart pointer class, so we’ll cover that one first. In the next lessons, we’ll cover std::shared_ptr and std::weak_ptr.


std::unique_ptr is the C++11 replacement for std::auto_ptr. It should be used to manage any dynamically allocated object that is not shared by multiple objects. That is, std::unique_ptr should completely own the object it manages, not share that ownership with other classes. std::unique_ptr lives in the <memory> header.

Let’s take a look at a simple smart pointer example:

Because the std::unique_ptr is allocated on the stack here, it’s guaranteed to eventually go out of scope, and when it does, it will delete the Resource it is managing.

Unlike std::auto_ptr, std::unique_ptr properly implements move semantics.

This prints:

Resource acquired
res1 is not null
res2 is null
Ownership transferred
res1 is null
res2 is not null
Resource destroyed

Because std::unique_ptr is designed with move semantics in mind, copy initialization and copy assignment are disabled. If you want to transfer the contents managed by std::unique_ptr, you must use move semantics. In the program above, we accomplish this via std::move (which converts res1 into an r-value, which triggers a move assignment instead of a copy assignment).

Accessing the managed object

std::unique_ptr has an overloaded operator* and operator-> that can be used to return the resource being managed. Operator* returns a reference to the managed resource, and operator-> returns a pointer.

Remember that std::unique_ptr may not always be managing an object -- either because it was created empty (using the default constructor or passing in a nullptr as the parameter), or because the resource it was managing got moved to another std::unique_ptr. So before we use either of these operators, we should check whether the std::unique_ptr actually has a resource. Fortunately, this is easy: std::unique_ptr has a cast to bool that returns true if the std::unique_ptr is managing a resource.

Here’s an example of this:

This prints:

Resource acquired
I am a resource
Resource destroyed

In the above program, we use the overloaded operator* to get the Resource object owned by std::unique_ptr res, which we then send to std::cout for printing.

std::unique_ptr and arrays

Unlike std::auto_ptr, std::unique_ptr is smart enough to know whether to use scalar delete or array delete, so std::unique_ptr is okay to use with both scalar objects and arrays.

However, std::array or std::vector (or std::string) are almost always better choices than using std::unique_ptr with a fixed array, dynamic array, or C-style string.

Rule: Favor std::array, std::vector, or std::string over a smart pointer managing a fixed array, dynamic array, or C-style string


C++14 comes with an additional function named std::make_unique(). This templated function constructs an object of the template type and initializes it with the arguments passed into the function.

The code above prints:


Use of std::make_unique() is optional, but is recommended over creating std::unique_ptr yourself. This is because code using std::make_unique is simpler, and it also requires less typing (when used with automatic type deduction). Furthermore it resolves an exception safety issue that can result from C++ leaving the order of evaluation for function arguments unspecified.


use std::make_unique() instead of creating std::unique_ptr and using new yourself

The exception safety issue in more detail

For those wondering what the “exception safety issue” mentioned above is, here’s a description of the issue.

Consider an expression like this one:

The compiler is given a lot of flexibility in terms of how it handles this call. It could create a new T, then call function_that_can_throw_exception(), then create the std::unique_ptr that manages the dynamically allocated T. If function_that_can_throw_exception() throws an exception, then the T that was allocated will not be deallocated, because the smart pointer to do the deallocation hasn’t been created yet. This leads to T being leaked.

std::make_unique() doesn’t suffer from this problem because the creation of the object T and the creation of the std::unique_ptr happen inside the std::make_unique() function, where there’s no ambiguity about order of execution.

Returning std::unique_ptr from a function

std::unique_ptr can be safely returned from a function by value:

In the above code, createResource() returns a std::unique_ptr by value. If this value is not assigned to anything, the temporary return value will go out of scope and the Resource will be cleaned up. If it is assigned (as shown in main()), in C++14 or earlier, move semantics will be employed to transfer the Resource from the return value to the object assigned to (in the above example, ptr), and in C++17 or newer, the return will be elided. This makes returning a resource by std::unique_ptr much safer than returning raw pointers!

In general, you should not return std::unique_ptr by pointer (ever) or reference (unless you have a specific compelling reason to).

Passing std::unique_ptr to a function

If you want the function to take ownership of the contents of the pointer, pass the std::unique_ptr by value. Note that because copy semantics have been disabled, you’ll need to use std::move to actually pass the variable in.

The above program prints:

Resource acquired
I am a resource
Resource destroyed
Ending program

Note that in this case, ownership of the Resource was transferred to takeOwnership(), so the Resource was destroyed at the end of takeOwnership() rather than the end of main().

However, most of the time, you won’t want the function to take ownership of the resource. Although you can pass a std::unique_ptr by reference (which will allow the function to use the object without assuming ownership), you should only do so when the called function might alter or change the object being managed.

Instead, it’s better to just pass the resource itself (by pointer or reference, depending on whether null is a valid argument). This allows the function to remain agnostic of how the caller is managing its resources. To get a raw resource pointer from a std::unique_ptr, you can use the get() member function:

The above program prints:

Resource acquired
I am a resource
Ending program
Resource destroyed

std::unique_ptr and classes

You can, of course, use std::unique_ptr as a composition member of your class. This way, you don’t have to worry about ensuring your class destructor deletes the dynamic memory, as the std::unique_ptr will be automatically destroyed when the class object is destroyed. However, do note that if your class object is dynamically allocated, the object itself is at risk for not being properly deallocated, in which case even a smart pointer won’t help.

Misusing std::unique_ptr

There are two easy ways to misuse std::unique_ptrs, both of which are easily avoided. First, don’t let multiple classes manage the same resource. For example:

While this is legal syntactically, the end result will be that both res1 and res2 will try to delete the Resource, which will lead to undefined behavior.

Second, don’t manually delete the resource out from underneath the std::unique_ptr.

If you do, the std::unique_ptr will try to delete an already deleted resource, again leading to undefined behavior.

Note that std::make_unique() prevents both of the above cases from happening inadvertently.

Quiz time

Question #1

Convert the following program from using a normal pointer to using std::unique_ptr where appropriate:

Show Solution

M.7 -- std::shared_ptr
M.5 -- std::move_if_noexcept

153 comments to M.6 — std::unique_ptr

  • michael oska


    in the second example in std::unique_ptr i think you should include utility header for std::move "even it will work without it" for consistency

  • crolis

    Can a unique_ptr be optimized out?

    At first I was worried about a memset operation, but now I'm worried about the unique_ptr itself as it might not be used. I'm not sure how post conditions are determined by the compiler. In my case, the user might provide a u_ptr to start, but might switch to one provided by the class.

  • Aphamino


    Why is there two consts in the following function signature (Question #1)?:

    I would understand if it was

    , but the way how it is now is beyond me. Can you please explain?

    • nascardriver

      The first `const` applies to the `Fraction`, the second `const` applies to the pointer.
      The second `const` has no meaning to the caller, it shouldn't be there, I've removed it. `const` parameters, ie. pass-by-value or pointer variables where the `const` doesn't apply to the data, can be used at function definitions, but should be avoided if the function definition also serves as a declaration.

  • gfvalvo

    Why is std::move() required when passing a std::unique_ptr TO a function:

    But NOT required when returning a std::unique_ptr FROM a function?

    Oh, wait. Returning a local stack variable. It will be destroyed anyway. So, returned as rvalue? Move semantics automatically selected to create the temporary?

  • yeokaiwei

    Hi Alex,
    Is this good practice for new developers?

    To use naked new?

  • Tony Kolarek

    I honestly thought smart pointers would be one of the most difficult things to learn on this tutorial. My god, how wrong I was!

    Thanks for the fantastic explainations!

  • Choi

    So what is the type of auto obj initialized with make_unique? I guess it could be 1 of 3 smartptr types, am i correct?
    Does make_unique make anonymous unique_ptr and move constructing auto(unique_ptr) with it?
    If so does it take time twice longer than normal unique_ptr with new T?

  • topherno

    You said make_unique solves the mentioned exception safety issue, which makes sense, but at the same time make_unique itself can throw an exception (unlike all unique_ptr ctors). From cppreference:

    May throw std::bad_alloc or any exception thrown by the constructor of T. If an exception is thrown, this function has no effect.

    So isn't this a drawback of make_unique compared to just using unique_ptr's ctors?

    • nascardriver

      If you use `std::unique_ptr`'s constructor with `new`, the `new` operator can throw `std::bad_alloc`. `std::make_unique` doesn't add any new exceptions, it just makes if more obvious where the `std::bad_alloc` is coming from.

  • Dong

    - Can you explain why the different results in section "Passing std::unique_ptr to a function".
    * First: Resource acquired
              I am a resource
              Resource destroyed
              Ending program
    * Second:
              Resource acquired
              I am a resource
              Ending program              
              Resource destroyed
    The third line "Ending program" is different in two example results. Thie first example I understand but the last one I do not understand. Can you give me some explain why? Thank for your comments.

  • OneNoobs

    Hi Alex and Nascardriver,
    Thanks for a great website. It really helps me a lot to learn C++.

    Please let me ask you a question.

    Regarding "In general, you should not return std::unique_ptr by pointer (ever) or reference (unless you have a specific compelling reason to).",
    Can you give me a bad example with "returning std::unique_ptr by pointer"?
    It is confusing to me whether you are talking about returning &l-value or

    instead of using make_unique<T>


  • salah


    std::make_unique<Resourse>() this function creates an object dynamcally and returns a moved address of type std::unique_ptr, right?

  • koe

    "In the next lesson, we’ll cover std::shared_ptr and std::weak_ptr."

    Should say "In the next two lessons we’ll cover std::shared_ptr and std::weak_ptr."

  • Sajid Khan

    Because main purpose of using smart pointers is to automatically delete allocated memory, and because transferring ownership uninitializes the previous object (which, most of the time is not expected), I don't get the point of transferring ownership at all.
    Why not use smart pointers just to allocate and initialize the resource, and pass resource to functions using a pointer or reference?

  • fensox

    Hello, would you have a moment please to elaborate on why, below, we should choose one instead of the other? This is from your std::make_unique section. Thank you.

    • nascardriver

      Please re-read section "std::unique_ptr and arrays" and "The exception safety issue in more detail". `std::make_unique` saves us from redundant type declarations and exceptions.

  • alven

    I have one question, the below code will cause issues. But when res1 is released ,the transferred resource should be null already. and after that , the res2 will also be released , does it also try to delete the deleted resource which has been set to null? if yes , will this delete cause some issues?
    Resource *res{ new Resource() };
    std::unique_ptr<Resource> res1{ res };
    std::unique_ptr<Resource> res2{ res };

    And another question is if the ownership of resource has been take from a temperary object, does it mean the resource in it is in nullptr state , then when the object is released, the destruct will also try to delete the nullptr ?


    • nascardriver

      `res1` and `res2` own the same resource. This is a contradiction to `std::unique_ptr` ownership model, where a pointer is a _unique_ owner. Each pointer will try to delete `res`. The pointer who deletes it first can do so, but the second attempt causes undefined behavior. Nothing will be set to `nullptr` in this example.
      Deleting something and setting it to `nullptr` are different things. Unless the pointer is used later, `delete`d pointers are usually left dangling.

  • Siva


    Can you please let me know if below code snippet provide me any compiler warnings
    This program worked fine on windows compiler but here two unique_ptr objects are
    pointing to same resource even though "make_unique" is used.

    int main()
        std::unique_ptr<Resource> ptr{std::make_unique<Resource>() };
        std::cout << "Ending program\n";
        // I'm misusing now , two pointer will take same resource
        Resource *res{ new Resource() };
        std::unique_ptr<Resource> res1{ std::make_unique<Resource>(std::move(*res)) };
        std::unique_ptr<Resource> res2{ std::make_unique<Resource>(std::move(*res)) };
        return 0;


    • nascardriver

      No warnings, but you're leaking `res`.
      `res1` and `res2` don't share a resource. By using `std::make_unique`, you're creating a new resource based on `res`. Altogether, you have 3 distinct resources: `res`, `res1`, and `res2`.
      `res` never gets deleted.

  • Tushar

    how do I initialize or assign value to f2[0]..f2[n]? like you did in the single dynamically allocated Fraction

    • Tushar

      Okay, I found the solution to the question.
      Correct me if i am wrong.
      we cannot use make_unique to intialize objects right??
      so we need to do something like what's written below? [line 10]

      • nascardriver

        You cannot use `std::make_unique` to initialize array elements. Individual objects are fine.
        If you want to initialize the elements, you can use a container, eg. `std::vector`, instead.

  • Serhii

    I don't quite understand the answer to the quiz N1.

    1) If your class has a smart pointer member, why should you try to avoid allocating objects of that class dynamically?

    Then how should we declare our class member instead of a smart pointer in case we need to dynamically allocate an object of that class? By declaring as a raw pointer?
    Please explain.

    Thanks very much in advance!

    • nascardriver

      That quiz didn't make sense. In the described scenario, memory would be leaked no matter how the class stored the data. I removed the quiz from the lessons. Thanks for bringing this to our attention!

  • Sapinder

    One confusion:
    How come '...(3,5)' and '...(4)' behave differently in "std::make_unique<Fraction>(3, 5)" and "std::make_unique<Fraction[]>(4)" respectively?

    • nascardriver

      This tells `std::make_unique` to create an array of `Fraction` rather than a single `Fraction` object.

  • David

    I have a question in the following program,in line 32,Does f2 be initialized with the move semantic or with copy semantic?
    In my opinion,in the "unique_ptr",the copy semantic is disabled,so it will use the move semantic rather than copy semantic.
    Does my concept be wrong?Thanks for replying.

    • nascardriver

      Most likely guaranteed copy elision, ie. no copy or move at all.
      In an implementation that can't guarantee copy elision, the move constructor is used.

  • David

    unique_ptr is a smart pointer that can used to manage dynamically allocated resource,and they won't create the object of template type.

    make_ptr is not a smart pointer,it is used to create the object of template type and initialize it with the arguments passed into the function.So make_ptr won't free the dynamically allocated resource automatically.

    Does my concept be wrong?
    Thanks for replying.

    • nascardriver

      `std::make_ptr` (Where `ptr` is `unique` or `shared`) creates a `std::unique_ptr` or `std::shared_ptr`. `std::make_ptr` is a function that makes it easier to create smart pointers. This doesn't change the behavior of the pointers. Their memory be freed when they die.

  • cnoob

    If I declare the print function like this:

    can I instantiate the Fraction object with smart pointer and print it the  like this?:

    • nascardriver

      If you don't need to transfer ownership, then you shouldn't. There's no reason for a `print` function to own whatever it's printing. Overusing smart pointers comes with a run-time cost.

  • Felix

    I'm wondering why the code uses direct initialization like the following line from the 2nd example:

    I guess the reason is mentioned in the Author's note from chapter "1.4 — Variable assignment and initialization", or is there a different reason?

    • nascardriver

      Some lessons, especially the later ones, haven't been updated to use brace initialization yet. I updated it, thanks for pointing it out!
      The first examples are still using direct initialization, because at that point `Resource` has not been defined and could potentially be a type with a list constructor.

  • Mojtabaa

    I've got two quick noobish questions:
    1_ Are we not allowing a `delete ptr` in the printFraction function the way the quiz question is solved? Isn't the goal of using smart unique pointers using their self-destruction feature and also not allowing their resources being accessed through multiple handles at once?
    2_ how about doing the quiz like this? how does it differ from the current solution given by Alex?

    • nascardriver

      1. I'm not sure what you mean. Smart pointers clean up after themselves, there should be no `delete`.

      2. In your version, `printFraction` only works when the caller has a smart pointer. If the caller doesn't have a smart pointer, they have to create one just to call `printFraction`, that's unnecessary. Smart pointers should only be passed to functions if you want to transfer/share ownership. `printFraction` doesn't care about who owns the `Fraction`, so it should take a regular pointer.

  • hellmet

    So, assuming T supports a move assignment and move constructor, move semantics implicitly happen when I return T by value or assign to a temporary.. and that's it, right? Explicit move semantics happen when I call std::move.

    And, a function with (T&& ..) is mostly used in move constructor and move assignment, rather than actual functions. I can't think of any use case of function that takes T&& as parameters.

    • nascardriver

      I'm not sure about the rules when a move is made, but what you said seems right.
      `T&&` is also used for perfect forwarding. If you've looked at some code or reference other than learncpp, you might have encountered `std::vector::emplace_back`, which can construct an element directly inside the vector without creating copies.

      • hellmet

        Right right! That makes sense now that you mention it! Given the type, the template class can create an object inside it and just 'move over' the elements into it.

        I'm sometimes a bit confused as to how this is different from a copy.. I'll think a bit more and ask if I have any more questions. Thank you!

  • Mrio

    In "Passing std::unique_ptr to a function", why is the takeOwnership signature

    instead of


    We are passing a r-value to takeOwnerships functions since we are using std::move()...

    I have tried the second approach and the output changes to:

    Any explanation?:)

    • nascardriver

      We want `takeOwnership` to take ownership of the resource.
      As you can tell from your output, if we pass the resource by rvalue reference into `takeOwnership`, `main` is still the owner of the resource.
      If we want `takeOwnership` to own the resource, `takeOwnership` has to have a real `std::unique_ptr`, not just a reference to one. When we use `std::move` to pass the resource and `takeOwnership` has a real `std::unique_ptr`, we're invoking the move constructor of that `std::unique_ptr`, which steals the resource from `main`'s `std::unique_ptr`.

      • Mrio

        Thanks a lot! I was confusing pass-by-reference with move semantics after reading the whole tutorial a bit too fast... After thinking about your answer I divided in 4 the ways to pass argument to a function (simplifying a lot and excluding pointers and const r-value references):

        - by l-value reference (T& parameter): The argument must be an l-value and it may be changed.

        - by constant l-value reference (const T& parameter): The argument can be any type of value and it will not be changed.

        - by r-value reference (T&& parameter): The argument  must be a r-value and ¿the function should leave it at a well-defined empty state like move assignment and move constructors do? ¿Where it is used aside from move constructors/assignments?

        - by value (T parameter): The argument can be of any type; if it is a l-value the copy constructor is called (depending on how the copy constructor is implemented, it can be a deep copy, like almost all l-values must support, or a shallow copy, for special objects like std::shared_ptr or if it was not implemented. With deep copy, changes inside the function will not affect the argument value), if it is an r-value then move constructor is called instead (if implemented, if not, the the copy constructor is used).

        ¿It is correct? I think that the first 3 are clear thanks to this awesome tutorial, the last one though (which seems the less complicated) is where I have more doubts.

        Thanks again!:)

        • nascardriver

          > the function should leave it at a well-defined empty state like move assignment and move constructors do
          In a valid state, ie. the object that was moved from doesn't cause any problems (eg. because it tries to delete something that it no longer owns). It doesn't have to be empty, it doesn't have to be usable, but it break anything. Leaving the object in a usable state is of course better than breaking it.

          > Where it is used aside from move constructors/assignments?
          Whenever you want to transfer ownership from one place to another. The direct way is via the constructor/assignment operator, but you can also transfer ownership by passing the object through different functions first.

          > if it is an r-value then move constructor is called
          No constructor is called. The copy is elided altogether.

          The rest seems good. If you have any further questions feel free to ask.

          • Mrio

            Thanks a lot nascardriver. Regarding your answer, I have just one more doubt. For example in the same "Passing std::unique_ptr to a function" when calling takeOwnership:

            It seems the move constructor of ptr is called at some point in my program althoug std::move(ptr) evaluates to a r-value and should be elided... (I used class "Auto_ptr4" to check it)

            I also check that calling this alone does not call the ptr move constructor:

            • nascardriver

              `std::move` produces an xvalue (A sub-category of rvalues. xvalues would die right after being used, so it's allowed to steal their resources). Passing an xvalue invokes the move constructor (If available).
              What I said before is true for prvalues (The other sub-category of rvalues), eg. when constructing the argument in the function call.

  • masterOfNothing

    So does std::make_unique return a r-value of std::unique_ptr? This was probably the most confusing.

Leave a Comment

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