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 (is responsible for) and manages another object via a pointer and subsequently 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 (
std::default_delete
) 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 described as
empty
.
There are two versions of
std::unique_ptr
:
- Manages a single object (e.g., allocated with new ).
- Manages a dynamically-allocated array of objects (e.g., allocated with new [ ] ).
The class satisfies the requirements of MoveConstructible and MoveAssignable , but of neither CopyConstructible nor 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
. (In contrast,
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
.
Feature-test macro | Value | Std | Feature |
---|---|---|---|
__cpp_lib_constexpr_memory
|
202202L | (C++23) |
constexpr
std::unique_ptr
|
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)
(C++20)
|
creates a unique pointer that manages a new object
(function template) |
(removed in C++20)
(C++20)
|
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 <cassert> #include <cstdio> #include <fstream> #include <iostream> #include <locale> #include <memory> #include <stdexcept> // helper class for runtime polymorphism demo below struct B { virtual ~B() = default; virtual void bar() { std::cout << "B::bar\n"; } }; 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; } // helper function for the custom deleter demo below void close_file(std::FILE* fp) { std::fclose(fp); } // unique_ptr-based linked list demo struct List { struct Node { int data; std::unique_ptr<Node> next; }; std::unique_ptr<Node> head; ~List() { // destroy list nodes sequentially in a loop, the default destructor // would have invoked its `next`'s destructor recursively, which would // cause stack overflow for sufficiently large lists. while (head) { auto next = std::move(head->next); head = std::move(next); } } void push(int data) { head = std::unique_ptr<Node>(new Node{data, std::move(head)}); } }; int main() { std::cout << "1) Unique ownership semantics demo\n"; { // Create a (uniquely owned) resource std::unique_ptr<D> p = std::make_unique<D>(); // Transfer ownership to `pass_through`, // which in turn transfers ownership back through the return value std::unique_ptr<D> q = pass_through(std::move(p)); // p is now in a moved-from 'empty' state, equal to nullptr assert(!p); } std::cout << "\n" "2) Runtime polymorphism demo\n"; { // Create a derived resource and point to it via base type std::unique_ptr<B> p = std::make_unique<D>(); // Dynamic dispatch works as expected p->bar(); } std::cout << "\n" "3) Custom deleter demo\n"; std::ofstream("demo.txt") << 'x'; // prepare the file to read { using unique_file_t = std::unique_ptr<std::FILE, decltype(&close_file)>; unique_file_t fp(std::fopen("demo.txt", "r"), &close_file); if (fp) std::cout << char(std::fgetc(fp.get())) << '\n'; } // `close_file()` called here (if `fp` is not null) std::cout << "\n" "4) Custom lambda-expression deleter and exception safety demo\n"; try { std::unique_ptr<D, void(*)(D*)> p(new D, [](D* ptr) { std::cout << "destroying from a custom deleter...\n"; delete ptr; }); throw std::runtime_error(""); // `p` would leak here if it were a plain pointer } catch (const std::exception&) { std::cout << "Caught exception\n"; } std::cout << "\n" "5) Array form of unique_ptr demo\n"; { std::unique_ptr<D[]> p(new D[3]); } // `D::~D()` is called 3 times std::cout << "\n" "6) Linked list demo\n"; { List wall; const int enough{1'000'000}; for (int beer = 0; beer != enough; ++beer) wall.push(beer); std::cout.imbue(std::locale("en_US.UTF-8")); std::cout << enough << " bottles of beer on the wall...\n"; } // destroys all the beers }
Possible output:
1) Unique ownership semantics demo D::D D::bar D::~D 2) Runtime polymorphism demo D::D D::bar D::~D 3) Custom deleter demo x 4) Custom lambda-expression deleter and exception safety demo D::D destroying from a custom deleter... D::~D Caught exception 5) Array form of unique_ptr demo D::D D::D D::D D::~D D::~D D::~D 6) Linked list demo 1,000,000 bottles of beer on the wall...
See also
(C++11)
|
smart pointer with shared object ownership semantics
(class template) |
(C++11)
|
weak reference to an object managed by
std::shared_ptr
(class template) |