std::unique_ptr
Defined in header <memory>
|
||
template< class T, |
(1) | (since C++11) |
template < class T, |
(2) | (since C++11) |
std::unique_ptr
is a smart pointer that owns and manages another object through a pointer and disposes of that object when the unique_ptr
goes out of scope.
The object is disposed of using the associated deleter when either of the following happens:
- the managing
unique_ptr
object is destroyed - the managing
unique_ptr
object is assigned another pointer via operator= or reset().
The object is disposed of using a potentially user-supplied deleter by calling get_deleter()(ptr). The default deleter uses the delete operator, which destroys the object and deallocates the memory.
A unique_ptr
may alternatively own no object, in which case it is called empty.
There are two versions of std::unique_ptr
:
The class satisfies the requirements of MoveConstructible and MoveAssignable, but not the requirements of either CopyConstructible or CopyAssignable.
Type requirements | ||
-Deleter must be FunctionObject or lvalue reference to a FunctionObject or lvalue reference to function, callable with an argument of type unique_ptr<T, Deleter>::pointer
|
Notes
Only non-const unique_ptr
can transfer the ownership of the managed object to another unique_ptr
. If an object's lifetime is managed by a const std::unique_ptr, it is limited to the scope in which the pointer was created.
std::unique_ptr
is commonly used to manage the lifetime of objects, including:
- providing exception safety to classes and functions that handle objects with dynamic lifetime, by guaranteeing deletion on both normal exit and exit through exception
- passing ownership of uniquely-owned objects with dynamic lifetime into functions
- acquiring ownership of uniquely-owned objects with dynamic lifetime from functions
- as the element type in move-aware containers, such as std::vector, which hold pointers to dynamically-allocated objects (e.g. if polymorphic behavior is desired)
std::unique_ptr
may be constructed for an incomplete type T
, such as to facilitate the use as a handle in the pImpl idiom. If the default deleter is used, T
must be complete at the point in code where the deleter is invoked, which happens in the destructor, move assignment operator, and reset
member function of std::unique_ptr
. (Conversely, std::shared_ptr can't be constructed from a raw pointer to incomplete type, but can be destroyed where T
is incomplete). Note that if T
is a class template specialization, use of unique_ptr
as an operand, e.g. !p requires T
's parameters to be complete due to ADL.
If T
is a derived class of some base B
, then std::unique_ptr<T> is implicitly convertible to std::unique_ptr<B>. The default deleter of the resulting std::unique_ptr<B> will use operator delete for B
, leading to undefined behavior unless the destructor of B
is virtual. Note that std::shared_ptr behaves differently: std::shared_ptr<B> will use the operator delete for the type T
and the owned object will be deleted correctly even if the destructor of B
is not virtual.
Unlike std::shared_ptr, std::unique_ptr
may manage an object through any custom handle type that satisfies NullablePointer. This allows, for example, managing objects located in shared memory, by supplying a Deleter
that defines typedef boost::offset_ptr pointer;
or another fancy pointer.
Member types
Member type | Definition |
pointer | std::remove_reference<Deleter>::type::pointer if that type exists, otherwise T* . Must satisfy NullablePointer
|
element_type | T , the type of the object managed by this unique_ptr
|
deleter_type | Deleter , the function object or lvalue reference to function or to function object, to be called from the destructor
|
Member functions
constructs a new unique_ptr (public member function) | |
destructs the managed object if such is present (public member function) | |
assigns the unique_ptr (public member function) | |
Modifiers | |
returns a pointer to the managed object and releases the ownership (public member function) | |
replaces the managed object (public member function) | |
swaps the managed objects (public member function) | |
Observers | |
returns a pointer to the managed object (public member function) | |
returns the deleter that is used for destruction of the managed object (public member function) | |
checks if there is an associated managed object (public member function) | |
Single-object version,
| |
dereferences pointer to the managed object (public member function) | |
Array version,
| |
provides indexed access to the managed array (public member function) |
Non-member functions
(C++14) |
creates a unique pointer that manages a new object (function template) |
compares to another unique_ptr or with nullptr (function template) | |
(C++20) |
outputs the value of the managed pointer to an output stream (function template) |
(C++11) |
specializes the std::swap algorithm (function template) |
Helper classes
(C++11) |
hash support for std::unique_ptr (class template specialization) |
Example
#include <iostream> #include <vector> #include <memory> #include <cstdio> #include <fstream> #include <cassert> #include <functional> struct B { virtual void bar() { std::cout << "B::bar\n"; } virtual ~B() = default; }; struct D : B { D() { std::cout << "D::D\n"; } ~D() { std::cout << "D::~D\n"; } void bar() override { std::cout << "D::bar\n"; } }; // a function consuming a unique_ptr can take it by value or by rvalue reference std::unique_ptr<D> pass_through(std::unique_ptr<D> p) { p->bar(); return p; } void close_file(std::FILE* fp) { std::fclose(fp); } int main() { std::cout << "unique ownership semantics demo\n"; { auto p = std::make_unique<D>(); // p is a unique_ptr that owns a D auto q = pass_through(std::move(p)); assert(!p); // now p owns nothing and holds a null pointer q->bar(); // and q owns the D object } // ~D called here std::cout << "Runtime polymorphism demo\n"; { std::unique_ptr<B> p = std::make_unique<D>(); // p is a unique_ptr that owns a D // as a pointer to base p->bar(); // virtual dispatch std::vector<std::unique_ptr<B>> v; // unique_ptr can be stored in a container v.push_back(std::make_unique<D>()); v.push_back(std::move(p)); v.emplace_back(new D); for(auto& p: v) p->bar(); // virtual dispatch } // ~D called 3 times std::cout << "Custom deleter demo\n"; std::ofstream("demo.txt") << 'x'; // prepare the file to read { std::unique_ptr<std::FILE, decltype(&close_file)> fp(std::fopen("demo.txt", "r"), &close_file); if(fp) // fopen could have failed; in which case fp holds a null pointer std::cout << (char)std::fgetc(fp.get()) << '\n'; } // fclose() called here, but only if FILE* is not a null pointer // (that is, if fopen succeeded) std::cout << "Custom lambda-expression deleter demo\n"; { std::unique_ptr<D, std::function<void(D*)>> p(new D, [](D* ptr) { std::cout << "destroying from a custom deleter...\n"; delete ptr; }); // p owns D p->bar(); } // the lambda above is called and D is destroyed std::cout << "Array form of unique_ptr demo\n"; { std::unique_ptr<D[]> p{new D[3]}; } // calls ~D 3 times }
Output:
unique ownership semantics demo D::D D::bar D::bar D::~D Runtime polymorphism demo D::D D::bar D::D D::D D::bar D::bar D::bar D::~D D::~D D::~D Custom deleter demo x Custom lambda-expression deleter demo D::D D::bar destroying from a custom deleter... D::~D Array form of unique_ptr demo D::D D::D D::D D::~D D::~D D::~D