0% found this document useful (0 votes)
69 views

M.6 - STD - Unique - PTR - Learn C++

The document discusses std::unique_ptr, a smart pointer class in C++ that manages dynamically allocated memory. std::unique_ptr ensures the memory is properly freed when the pointer goes out of scope. It can be used to manage a single dynamically allocated object and completely owns the object, without sharing ownership. The document provides examples of initializing and using std::unique_ptr, accessing the managed object, moving ownership between pointers, and using std::unique_ptr with arrays and std::make_unique.

Uploaded by

njb25bcnqf
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
69 views

M.6 - STD - Unique - PTR - Learn C++

The document discusses std::unique_ptr, a smart pointer class in C++ that manages dynamically allocated memory. std::unique_ptr ensures the memory is properly freed when the pointer goes out of scope. It can be used to manage a single dynamically allocated object and completely owns the object, without sharing ownership. The document provides examples of initializing and using std::unique_ptr, accessing the managed object, moving ownership between pointers, and using std::unique_ptr with arrays and std::make_unique.

Uploaded by

njb25bcnqf
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 20

05/05/2021 M.

6 — std::unique_ptr | Learn C++

M.6 — std::unique_ptr
BY ALEX ON MARCH 15TH, 2017 | LAST MODIFIED BY ALEX ON APRIL 30TH, 2021

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.

1 #include <iostream>
2
3 void someFunction()
4 {
5 auto *ptr{ new Resource() };
6
7 int x{};
8 std::cout << "Enter an integer: ";
9 std::cin >> x;
10
11 if (x == 0)
12 throw 0; // the function returns early, and ptr won’t be deleted!
13
14 // do stuff with ptr here
15
16 delete ptr;
17 }

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
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:

1 #include <iostream>
2 #include <memory> // for std::unique_ptr
3
4 class Resource
5 {
6 public:
7 Resource() { std::cout << "Resource acquired\n"; }
8 ~Resource() { std::cout << "Resource destroyed\n"; }
9 };
10
11 int main()
12 {
13 // allocate a Resource object and have it owned by std::unique_ptr

https://www.learncpp.com/cpp-tutorial/stdunique_ptr/ 1/20
05/05/2021 M.6 — std::unique_ptr | Learn C++
14 std::unique_ptr<Resource> res{ new Resource() };
15
16 return 0;
17 } // res goes out of scope here, and the allocated Resource is destroyed

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.

1 #include <iostream>
2 #include <memory> // for std::unique_ptr
3 #include <utility> // for std::move
4
5 class Resource
6 {
7 public:
8 Resource() { std::cout << "Resource acquired\n"; }
9 ~Resource() { std::cout << "Resource destroyed\n"; }
10 };
11
12 int main()
13 {
14 std::unique_ptr<Resource> res1{ new Resource{} }; // Resource created here
15 std::unique_ptr<Resource> res2{}; // Start as nullptr
16
17 std::cout << "res1 is " << (static_cast<bool>(res1) ? "not null\n" : "null\n");
18 std::cout << "res2 is " << (static_cast<bool>(res2) ? "not null\n" : "null\n");
19
20 // res2 = res1; // Won't compile: copy assignment is disabled
21 res2 = std::move(res1); // res2 assumes ownership, res1 is set to null
22
23 std::cout << "Ownership transferred\n";
24
25 std::cout << "res1 is " << (static_cast<bool>(res1) ? "not null\n" : "null\n");
26 std::cout << "res2 is " << (static_cast<bool>(res2) ? "not null\n" : "null\n");
27
28 return 0;
29 } // Resource destroyed here when res2 goes out of scope

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.
https://www.learncpp.com/cpp-tutorial/stdunique_ptr/ 2/20
05/05/2021 M.6 — std::unique_ptr | Learn C++
Here’s an example of this:

1 #include <iostream>
2 #include <memory> // for std::unique_ptr
3
4 class Resource
5 {
6 public:
7 Resource() { std::cout << "Resource acquired\n"; }
8 ~Resource() { std::cout << "Resource destroyed\n"; }
9 friend std::ostream& operator<<(std::ostream& out, const Resource &res)
10 {
11 out << "I am a resource\n";
12 return out;
13 }
14 };
15
16 int main()
17 {
18 std::unique_ptr<Resource> res{ new Resource{} };
19
20 if (res) // use implicit cast to bool to ensure res contains a Resource
21 std::cout << *res << '\n'; // print the Resource that res is owning
22
23 return 0;
24 }

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

std::make_unique

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.

1 #include <memory> // for std::unique_ptr and std::make_unique


2 #include <iostream>
3
4 class Fraction
5 {
6 private:
7 int m_numerator{ 0 };
8 int m_denominator{ 1 };
9
10 public:
11 Fraction(int numerator = 0, int denominator = 1) :
12 m_numerator{ numerator }, m_denominator{ denominator }
13 {
14 }

https://www.learncpp.com/cpp-tutorial/stdunique_ptr/ 3/20
05/05/2021 M.6 — std::unique_ptr | Learn C++
15
16 friend std::ostream& operator<<(std::ostream& out, const Fraction &f1)
17 {
18 out << f1.m_numerator << '/' << f1.m_denominator;
19 return out;
20 }
21 };
22
23
24 int main()
25 {
26 // Create a single dynamically allocated Fraction with numerator 3 and denominator 5
27 // We can also use automatic type deduction to good effect here
28 auto f1{ std::make_unique<Fraction>(3, 5) };
29 std::cout << *f1 << '\n';
30
31 // Create a dynamically allocated array of Fractions of length 4
32 auto f2{ std::make_unique<Fraction[]>(4) };
33 std::cout << f2[0] << '\n';
34
35 return 0;
36 }

The code above prints:

3/5
0/1

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.

Rule

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:

1 some_function(std::unique_ptr<T>(new T), function_that_can_throw_exception());

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:

1 std::unique_ptr<Resource> createResource()
2 {
3 return std::make_unique<Resource>();
4 }
5
6 int main()

https://www.learncpp.com/cpp-tutorial/stdunique_ptr/ 4/20
05/05/2021 M.6 — std::unique_ptr | Learn C++
7 {
8 auto ptr{ createResource() };
9
10 // do whatever
11
12 return 0;
13 }

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.

1 #include <memory> // for std::unique_ptr


2 #include <utility> // for std::move
3
4 class Resource
5 {
6 public:
7 Resource() { std::cout << "Resource acquired\n"; }
8 ~Resource() { std::cout << "Resource destroyed\n"; }
9 friend std::ostream& operator<<(std::ostream& out, const Resource &res)
10 {
11 out << "I am a resource\n";
12 return out;
13 }
14 };
15
16 void takeOwnership(std::unique_ptr<Resource> res)
17 {
18 if (res)
19 std::cout << *res << '\n';
20 } // the Resource is destroyed here
21
22 int main()
23 {
24 auto ptr{ std::make_unique<Resource>() };
25
26 // takeOwnership(ptr); // This doesn't work, need to use move semantics
27 takeOwnership(std::move(ptr)); // ok: use move semantics
28
29 std::cout << "Ending program\n";
30
31 return 0;
32 }

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().

https://www.learncpp.com/cpp-tutorial/stdunique_ptr/ 5/20
05/05/2021 M.6 — std::unique_ptr | Learn C++
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:

1 #include <memory> // for std::unique_ptr


2 #include <iostream>
3
4 class Resource
5 {
6 public:
7 Resource() { std::cout << "Resource acquired\n"; }
8 ~Resource() { std::cout << "Resource destroyed\n"; }
9
10 friend std::ostream& operator<<(std::ostream& out, const Resource &res)
11 {
12 out << "I am a resource\n";
13 return out;
14 }
15 };
16
17 // The function only uses the resource, so we'll accept a pointer to the resource, not a r
eference to the whole std::unique_ptr<Resource>
18 void useResource(Resource *res)
19 {
20 if (res)
21 std::cout << *res << '\n';
22 }
23
24 int main()
25 {
26 auto ptr{ std::make_unique<Resource>() };
27
28 useResource(ptr.get()); // note: get() used here to get a pointer to the Resource
29
30 std::cout << "Ending program\n";
31
32 return 0;
33 } // The Resource is destroyed here

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:

1 Resource *res{ new Resource() };


2 std::unique_ptr<Resource> res1{ res };

https://www.learncpp.com/cpp-tutorial/stdunique_ptr/ 6/20
05/05/2021 M.6 — std::unique_ptr | Learn C++
3 std::unique_ptr<Resource> res2{ res };

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.

1 Resource *res{ new Resource() };


2 std::unique_ptr<Resource> res1{ res };
3 delete res;

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:

1 #include <iostream>
2
3 class Fraction
4 {
5 private:
6 int m_numerator{ 0 };
7 int m_denominator{ 1 };
8
9 public:
10 Fraction(int numerator = 0, int denominator = 1) :
11 m_numerator{ numerator }, m_denominator{ denominator }
12 {
13 }
14
15 friend std::ostream& operator<<(std::ostream& out, const Fraction &f1)
16 {
17 out << f1.m_numerator << '/' << f1.m_denominator;
18 return out;
19 }
20 };
21
22 void printFraction(const Fraction* ptr)
23 {
24 if (ptr)
25 std::cout << *ptr << '\n';
26 }
27
28 int main()
29 {
30 auto *ptr{ new Fraction{ 3, 5 } };
31
32 printFraction(ptr);
33
34 delete ptr;
35
36 return 0;
37 }

Show Solution

M.7 -- std::shared_ptr

https://www.learncpp.com/cpp-tutorial/stdunique_ptr/ 7/20
05/05/2021 M.6 — std::unique_ptr | Learn C++

Index

M.5 -- std::move_if_noexcept

C++ TUTORIAL | PRINT THIS POST

153 comments to M.6 — std::unique_ptr

« Older Comments 1 2

michael oska
April 30, 2021 at 2:00 am · Reply

hi,

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
March 24, 2021 at 8:17 am · Reply

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.

1 class ArduinoPrinter {
2 private:
3 std::unique_ptr<unsigned char[], decltype(free)*> _buf{ nullptr, free }; // will th
is stop it from being optimized out?
4
5 public:
6 ArduinoPrinter(......
7 // this is in the constructor
8 if (useCalloc)
9 _buf.reset(
10 reinterpret_cast<unsigned char*>(calloc(_alloc, sizeof(unsigned char)))
11 );
12
13 if (_buf) {
14 memset(_buf.get(), 0, _alloc); // could this be optimized out
15 if (_buf[0] == 0) // without post conditions?
16 _buf[0] = 1; _buf[0] = 0;
17 }
18 };

Aphamino
March 20, 2021 at 12:30 pm · Reply

Hi!

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

1 void printFraction(const Fraction* const ptr)


2 {
3 if (ptr)
4 std::cout << *ptr << '\n';

https://www.learncpp.com/cpp-tutorial/stdunique_ptr/ 8/20
05/05/2021 M.6 — std::unique_ptr | Learn C++
5 }

I would understand if it was

1 const Fraction* ptr

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

nascardriver
March 21, 2021 at 2:06 am · Reply

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.

Aphamino
March 21, 2021 at 6:52 am · Reply

Ahh, okay. I didn't know that you can "const-lock" both the type AND the parameter.

gfvalvo
January 22, 2021 at 5:11 am · Reply

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

1 // takeOwnership(ptr); // This doesn't work, need to use move semantics


2 takeOwnership(std::move(ptr)); // ok: use move semantics

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

1 std::unique_ptr<Resource> createResource()
2 {
3 return std::make_unique<Resource>();
4 }

EDIT:
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
January 8, 2021 at 8:18 pm · Reply

Hi Alex,
Is this good practice for new developers?

To use naked new?

1 std::unique_ptr<Resource> res{ new Resource() };

yeokaiwei
January 8, 2021 at 9:29 pm · Reply

Oh, the Quiz will teach you to remove "new and delete".

Tony Kolarek
November 7, 2020 at 11:37 am · Reply

I honestly thought smart pointers would be one of the most difficult things to learn on this tutorial. My
god, how wrong I was!
https://www.learncpp.com/cpp-tutorial/stdunique_ptr/ 9/20
05/05/2021 M.6 — std::unique_ptr | Learn C++
Thanks for the fantastic explainations!

Choi
October 22, 2020 at 3:23 pm · Reply

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?

nascardriver
October 23, 2020 at 6:24 am · Reply

`std::make_unique` returns a `std::unique_ptr`. No move is involved, the return is elided.


`std::make_unique` is not slower than manually constructing a `std::unique_ptr`.

Choi
October 23, 2020 at 9:28 pm · Reply

Oh, so it's just a signal to make it once? got it

topherno
September 22, 2020 at 6:32 am · Reply

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
September 26, 2020 at 4:10 am · Reply

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
September 4, 2020 at 7:38 pm · Reply

- 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.

https://www.learncpp.com/cpp-tutorial/stdunique_ptr/ 10/20
05/05/2021 M.6 — std::unique_ptr | Learn C++

nascardriver
September 5, 2020 at 2:05 am · Reply

`ptr` dies at the end of `main`. When that happens "Ending program" has already been
printed.

OneNoobs
August 4, 2020 at 12:38 pm · Reply

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

1 return (std::unique_ptr<T> myClass{new T{}});

instead of using make_unique<T>

Thanks.

nascardriver
August 6, 2020 at 5:12 am · Reply

I suppose Alex meant these 2

1 std::unique_ptr<T>& fn();
2 std::unique_ptr<T>* fn();

I don't see why you'd want to do that or why Alex though it was worthwhile to point them out.

OneNoobs
August 8, 2020 at 12:40 pm · Reply

Ah, me neither. Thanks for your answer! :)

salah
July 14, 2020 at 9:08 am · Reply

Hi,

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

koe
July 11, 2020 at 5:23 pm · Reply

"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
June 30, 2020 at 7:33 am · Reply

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
https://www.learncpp.com/cpp-tutorial/stdunique_ptr/ 11/20
05/05/2021 M.6 — std::unique_ptr | Learn C++
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?

1 #include <iostream>
2 #include <memory> // for std::unique_ptr
3
4 class Resource
5 {
6 public:
7 Resource() { std::cout << "Resource acquired\n"; }
8 ~Resource() { std::cout << "Resource destroyed\n"; }
9 friend std::ostream& operator<<(std::ostream& out, const Resource &)
10 {
11 out << "I am a resource\n";
12 return out;
13 }
14 };
15
16 void utilizeResource(Resource *res) //or void utilizeResource(std::unique_ptr<Resource>
17 &res)
18 {
19 std::cout << "'res' inside function : " << *res;
20 }
21
22 int main()
23 {
24 std::unique_ptr<Resource> res{ new Resource{} };
25
26 //does not transfer ownership
27 utilizeResource(&*res); //or utilizeResource(res);
28
29 if (res)
30 std::cout << "'res' is still initialized after function call\n";
31
32 return 0;
}

Sajid Khan
July 1, 2020 at 12:36 am · Reply

Sorry I just read the 'Passing std::unique_ptr to a function' section again, You have already
made everything clear

fensox
June 23, 2020 at 6:48 am · Reply

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.

1 // learncpp.com's example
2 std::unique_ptr<Fraction> f1{ std::make_unique<Fraction>(3, 5) };
3
4 // why is this not as good?
5 std::unique_ptr<Fraction> f1{ new Fraction(3, 5) };

nascardriver
June 23, 2020 at 7:49 am · Reply

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
https://www.learncpp.com/cpp-tutorial/stdunique_ptr/ 12/20
05/05/2021 M.6 — std::unique_ptr | Learn C++
June 22, 2020 at 10:47 pm · Reply

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 ?

thanks.

nascardriver
June 23, 2020 at 5:36 am · Reply

`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
May 2, 2020 at 1:09 am · Reply

Hi,

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>() };
donottakeOwnership(std::move(ptr));

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;
}

Regards,
Siva.

nascardriver
May 2, 2020 at 4:38 am · Reply

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.

https://www.learncpp.com/cpp-tutorial/stdunique_ptr/ 13/20
05/05/2021 M.6 — std::unique_ptr | Learn C++

Tushar
April 21, 2020 at 8:21 pm · Reply

1 int main()
2 {
3 // Create a single dynamically allocated Fraction with numerator 3 and denominator
4 5
5 std::unique_ptr<Fraction> f1{ std::make_unique<Fraction>(3, 5) };
6 std::cout << *f1 << '\n';
7
8 // Create a dynamically allocated array of Fractions of length 4
9 // We can also use automatic type deduction to good effect here
10 auto f2{ std::make_unique<Fraction[]>(4) };
11 std::cout << f2[0] << '\n';
12
return 0;

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

Tushar
April 22, 2020 at 7:26 pm · Reply

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]

1 int main()
2 {
3 // Create a single dynamically allocated Fraction with numerator 3 and denomi
4 nator 5
5 std::unique_ptr<Fraction> f1{ std::make_unique<Fraction>(3, 5) };
6 std::cout << *f1 << '\n';
7
8 // Create a dynamically allocated array of Fractions of length 4
9 // We can also use automatic type deduction to good effect here
10 auto f2{ std::make_unique<Fraction[]>(4) };
11 f2[1]=Fraction(23,55);
12 std::cout << f2[0] << '\n';
13 std::cout << f2[1] << '\n';
14
15 return 0;
}

nascardriver
April 27, 2020 at 7:57 am · Reply

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
March 26, 2020 at 4:42 pm · Reply

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.
https://www.learncpp.com/cpp-tutorial/stdunique_ptr/ 14/20
05/05/2021 M.6 — std::unique_ptr | Learn C++
Thanks very much in advance!

nascardriver
March 27, 2020 at 6:11 am · Reply

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
March 15, 2020 at 1:04 am · Reply

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
March 15, 2020 at 2:19 am · Reply

1 std::make_unique<Fraction[]>(4)
2 // ^^

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

David
February 15, 2020 at 8:57 pm · Reply

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.

1 #include <memory> // for std::unique_ptr and std::make_unique


2 #include <iostream>
3
4 class Fraction
5 {
6 private:
7 int m_numerator{ 0 };
8 int m_denominator{ 1 };
9
10 public:
11 Fraction(int numerator = 0, int denominator = 1) :
12 m_numerator{ numerator }, m_denominator{ denominator }
13 {
14 }
15
16 friend std::ostream& operator<<(std::ostream& out, const Fraction& f1)
17 {
18 out << f1.m_numerator << "/" << f1.m_denominator;
19 return out;
20 }
21 };
22
23
24 int main()
25 {
26 // Create a single dynamically allocated Fraction with numerator 3 and denominator
27 5
28 std::unique_ptr<Fraction> f1{ std::make_unique<Fraction>(3, 5) };
https://www.learncpp.com/cpp-tutorial/stdunique_ptr/ 15/20
05/05/2021 M.6 — std::unique_ptr | Learn C++
29 std::cout << *f1 << '\n';
30
31 // Create a dynamically allocated array of Fractions of length 4
32 // We can also use automatic type deduction to good effect here
33 auto f2{ std::make_unique<Fraction[]>(4) };
34 std::cout << f2[0] << '\n';
35
36 return 0;
}

nascardriver
February 16, 2020 at 1:14 am · Reply

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
February 14, 2020 at 7:55 pm · Reply

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
February 15, 2020 at 1:16 am · Reply

`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
January 27, 2020 at 1:16 pm · Reply

If I declare the print function like this:

1 void printFraction(const std::unique_ptr<Fraction> ptr)


2 {
3 if (ptr)
4 std::cout << *ptr << '/n';
5 }

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

1 int main()
2 {
3 printFraction(std::make_unique<Fraction>(3, 5));
4
5 return 0;
6 }

nascardriver
January 28, 2020 at 2:25 am · Reply

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.

https://www.learncpp.com/cpp-tutorial/stdunique_ptr/ 16/20
05/05/2021 M.6 — std::unique_ptr | Learn C++

Felix
January 27, 2020 at 7:01 am · Reply

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

1 std::unique_ptr<Resource> res(new Resource);

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
January 27, 2020 at 8:04 am · Reply

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
December 22, 2019 at 10:34 pm · Reply

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?

1 void printFraction(std::unique_ptr<Fraction>& ptr)

nascardriver
December 23, 2019 at 4:25 am · Reply

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
November 30, 2019 at 9:54 am · Reply

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
December 2, 2019 at 3:49 am · Reply

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.

https://www.learncpp.com/cpp-tutorial/stdunique_ptr/ 17/20
05/05/2021 M.6 — std::unique_ptr | Learn C++

hellmet
December 2, 2019 at 4:57 am · Reply

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
November 4, 2019 at 4:08 am · Reply

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

1 void takeOwnership(std::unique_ptr<Resource> res)

instead of

1 void takeOwnership(std::unique_ptr<Resource>&& res)

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:

1 Resource acquired
2 I am a resource
3 Ending program
4 Resource destroyed

Any explanation?:)

nascardriver
November 4, 2019 at 4:29 am · Reply

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
November 4, 2019 at 8:37 am · Reply

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
https://www.learncpp.com/cpp-tutorial/stdunique_ptr/ 18/20
05/05/2021 M.6 — std::unique_ptr | Learn C++
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
November 4, 2019 at 9:35 am · Reply

> 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
November 4, 2019 at 9:58 am · Reply

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:

1 takeOwnership(std::move(ptr))

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:

1 std::move(ptr);

nascardriver
November 5, 2019 at 1:32 am · Reply

`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.

1 // No copy/move
2 takeOwnership(std::make_unique<Resource>());

masterOfNothing
October 26, 2019 at 8:04 am · Reply
https://www.learncpp.com/cpp-tutorial/stdunique_ptr/ 19/20
05/05/2021 M.6 — std::unique_ptr | Learn C++
So does std::make_unique return a r-value of std::unique_ptr? This was probably the most confusing.

nascardriver
October 26, 2019 at 8:12 am · Reply

All functions calls that don't return a reference are r-values. `std::make_unique` returns an
`std::unique_ptr` by value, so the call is an r-value.
The `std::unique_ptr` isn't returned by reference. It's created by `std::make_unique`.

masterOfNothing
October 29, 2019 at 9:00 am · Reply

That's better. Thanks.

« Older Comments 1 2

https://www.learncpp.com/cpp-tutorial/stdunique_ptr/ 20/20

You might also like