Unique ownership (std::unique_ptr)
suggest changeA std::unique_ptr
is a class template that manages the lifetime of a dynamically stored object. Unlike for std::shared_ptr
, the dynamic object is owned by only one instance of a std::unique_ptr
at any time,
// Creates a dynamic int with value of 20 owned by a unique pointer
std::unique_ptr<int> ptr = std::make_unique<int>(20);
(Note: std::unique_ptr
is available since C++11 and std::make_unique
since C++14.)
Only the variable ptr
holds a pointer to a dynamically allocated int
. When a unique pointer that owns an object goes out of scope, the owned object is deleted, i.e. its destructor is called if the object is of class type, and the memory for that object is released.
To use std::unique_ptr
and std::make_unique
with array-types, use their array specializations:
// Creates a unique_ptr to an int with value 59
std::unique_ptr<int> ptr = std::make_unique<int>(59);
// Creates a unique_ptr to an array of 15 ints
std::unique_ptr<int[]> ptr = std::make_unique<int[]>(15);
You can access the std::unique_ptr
just like a raw pointer, because it overloads those operators.
You can transfer ownership of the contents of a smart pointer to another pointer by using std::move
, which will cause the original smart pointer to point to nullptr
.
// 1. std::unique_ptr
std::unique_ptr<int> ptr = std::make_unique<int>();
// Change value to 1
*ptr = 1;
// 2. std::unique_ptr (by moving 'ptr' to 'ptr2', 'ptr' doesn't own the object anymore)
std::unique_ptr<int> ptr2 = std::move(ptr);
int a = *ptr2; // 'a' is 1
int b = *ptr; // undefined behavior! 'ptr' is 'nullptr'
// (because of the move command above)
Passing unique_ptr
to functions as parameter:
void foo(std::unique_ptr<int> ptr)
{
// Your code goes here
}
std::unique_ptr<int> ptr = std::make_unique<int>(59);
foo(std::move(ptr))
Returning unique_ptr
from functions. This is the preferred C++11 way of writing factory functions, as it clearly conveys the ownership semantics of the return: the caller owns the resulting unique_ptr
and is responsible for it.
std::unique_ptr<int> foo()
{
std::unique_ptr<int> ptr = std::make_unique<int>(59);
return ptr;
}
std::unique_ptr<int> ptr = foo();
Compare this to:
int* foo_cpp03();
int* p = foo_cpp03(); // do I own p? do I have to delete it at some point?
// it's not readily apparent what the answer is.
The class template make_unique
is provided since C++14. It’s easy to add it manually to C++11 code:
template<typename T, typename... Args>
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
make_unique(Args&&... args)
{ return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); }
// Use make_unique for arrays
template<typename T>
typename std::enable_if<std::is_array<T>::value, std::unique_ptr<T>>::type
make_unique(size_t n)
{ return std::unique_ptr<T>(new typename std::remove_extent<T>::type[n]()); }
Unlike the dumb smart pointer (std::auto_ptr
), unique_ptr
can also be instantiated with vector allocation (not std::vector
). Earlier examples were for scalar allocations. For example to have a dynamically allocated integer array for 10 elements, you would specify int[]
as the template type (and not just int
):
std::unique_ptr<int[]> arr_ptr = std::make_unique<int[]>(10);
Which can be simplified with:
auto arr_ptr = std::make_unique<int[]>(10);
Now, you use arr_ptr
as if it is an array:
arr_ptr[2] = 10; // Modify third element
You need not to worry about de-allocation. This template specialized version calls constructors and destructors appropriately. Using vectored version of unique_ptr
or a vector
itself - is a personal choice.
In versions prior to C++11, std::auto_ptr
was available. Unlike unique_ptr
it is allowed to copy auto_ptr
s, upon which the source ptr
will lose the ownership of the contained pointer and the target receives it.