std::unique...::unique_ptr(3)
β¨ NAME β¨
std::unique_ptr::unique_ptr β std::unique_ptr::unique_ptr, bestie. This is the std::unique...::unique_ptr(3) page from the C++ Standard Libary manual, and we are decoding every single constructor overload together. No cap, itβs giving smart-pointer main character energy. π
π¦ Synopsis π¦
okay so hereβs the whole synopsis, and yes every overload, every noexcept, every constexpr since C++23, and every βremoved in C++17β note is staying exactly where it belongs:
members of the primary template, unique_ptr<T>
constexpr unique_ptr() noexcept; (1)
constexpr unique_ptr( std::nullptr_t ) noexcept;
explicit unique_ptr( pointer p ) noexcept; (2)
(constexpr since C++23)
unique_ptr( pointer p, /* see below */ d1 ) noexcept; (3)
(constexpr since C++23)
unique_ptr( pointer p, /* see below */ d2 ) noexcept; (4)
(constexpr since C++23)
unique_ptr( unique_ptr&& u ) noexcept; (5)
(constexpr since C++23)
template< class U, class E > (6)
(constexpr since C++23)
unique_ptr( unique_ptr<U, E>&& u ) noexcept;
unique_ptr( const unique_ptr& ) = delete; (7)
template< class U > (8) (removed in C++17)
unique_ptr( std::auto_ptr<U>&& u ) noexcept;
members of the specialization for arrays,
unique_ptr<T[]>
constexpr unique_ptr() noexcept; (1)
constexpr unique_ptr( std::nullptr_t ) noexcept;
template< class U > explicit unique_ptr( U p ) noexcept; (2)
(constexpr since C++23)
template< class U > unique_ptr( U p, /* see below */ d1 (3)
(constexpr since C++23)
) noexcept;
template< class U > unique_ptr( U p, /* see below */ d2 (4)
(constexpr since C++23)
) noexcept;
unique_ptr( unique_ptr&& u ) noexcept; (5)
(constexpr since C++23)
template< class U, class E > (6)
(constexpr since C++23)
unique_ptr( unique_ptr<U, E>&& u ) noexcept;
unique_ptr( const unique_ptr& ) = delete; (7)
π«Ά The overloads, decoded one by one
- 1) Constructs a
std::unique_ptrthat owns nothing. Value-initializes the stored pointer and the stored deleter. Requires thatDeleterisDefaultConstructibleand that construction does not throw an exception. These overloads participate in overload resolution only ifstd::is_default_constructible<Deleter>::valueis true andDeleteris not a pointer type. - 2) Constructs a
std::unique_ptrwhich ownsp, initializing the stored pointer withpand value-initializing the stored deleter. Requires thatDeleterisDefaultConstructibleand that construction does not throw an exception. This overload participates in overload resolution only ifstd::is_default_constructible<Deleter>::valueis true andDeleteris not a pointer type.
This constructor is not selected by class template argument deduction. (since C++17)
- 3, 4) Constructs a
std::unique_ptrobject which ownsp, initializing the stored pointer withpand initializing a deleterDas below (depends upon whetherDis a reference type).
a) If D is non-reference type A, then the signatures are:
unique_ptr(pointer p, const A& d) (1) (requires that Deleter is
noexcept; nothrow-CopyConstructible)
unique_ptr(pointer p, A&& d) (2) (requires that Deleter is
noexcept; nothrow-MoveConstructible)
b) If D is an lvalue-reference type A&, then the signatures are:
unique_ptr(pointer p, A& d) noexcept; (1)
unique_ptr(pointer p, A&& d) = delete; (2)
c) If D is an lvalue-reference type const A&, then the signatures are:
unique_ptr(pointer p, const A& d) noexcept; (1)
unique_ptr(pointer p, const A&& d) = delete; (2)
In all cases the deleter is initialized from std::forward<decltype(d)>(d). These overloads participate in overload resolution only if std::is_constructible<D, decltype(d)>::value is true.
These two constructors are not selected by class template argument deduction. (since C++17)
- 2-4) In the specialization for arrays, they behave the same as the constructors that take a pointer parameter in the primary template, except that they additionally do not participate in overload resolution unless one of the following is true:
Uis the same type aspointer, orUisstd::nullptr_t, orpointeris the same type aselement_type*andUis some pointer typeV*such thatV(*)[]is implicitly convertible toelement_type(*)[].
- 5) Constructs a
unique_ptrby transferring ownership fromuto*thisand stores the null pointer inu. This constructor only participates in overload resolution ifstd::is_move_constructible<Deleter>::valueis true. IfDeleteris not a reference type, requires that it isnothrow-MoveConstructible(ifDeleteris a reference,get_deleter()andu.get_deleter()after move construction reference the same value). - 6) Constructs a
unique_ptrby transferring ownership fromuto*this, whereuis constructed with a specified deleter (E). It depends upon whetherEis a reference type, as following:- a) if
Eis a reference type, this deleter is copy constructed fromuβs deleter (requires that this construction does not throw), - b) if
Eis a non-reference type, this deleter is move constructed fromuβs deleter (requires that this construction does not throw).
- a) if
This constructor only participates in overload resolution if all of the following is true:
- a)
unique_ptr<U, E>::pointeris implicitly convertible topointer, - b)
Uis not an array type, - c) either
Deleteris a reference type andEis the same type asD, orDeleteris not a reference type andEis implicitly convertible toD.
- 6) In the specialization for arrays, it behaves the same as in the primary template, except that it will only participate in overload resolution if all of the following is true:
Uis an array type,pointeris the same type aselement_type*,unique_ptr<U,E>::pointeris the same type asunique_ptr<U,E>::element_type*,unique_ptr<U,E>::element_type(*)[]is convertible toelement_type(*)[],- either
Deleteris a reference type andEis the same type asDeleter, orDeleteris not a reference type andEis implicitly convertible toDeleter.
- 7) Copy constructor is explicitly deleted. π« No copying, periodt.
- 8) Constructs a
unique_ptrwhere the stored pointer is initialized withu.release()and the stored deleter is value-initialized. This constructor only participates in overload resolution ifU*is implicitly convertible toT*andDeleteris the same type asstd::default_delete<T>.
π Also: overload 8 is the one marked removed in C++17 up in the synopsis, bestie. Keep that in mind.
π Parameters π
pβ a pointer to an object to managed1,d2β a deleter to use to destroy the objectuβ another smart pointer to acquire the ownership from
πΈ Notes πΈ
- (since C++14) Instead of using the overload (2) together with
new, it is often a better idea to usestd::make_unique<T>. std::unique_ptr<Derived>is implicitly convertible tostd::unique_ptr<Base>through the overload (6) (because both the managed pointer andstd::default_deleteare implicitly convertible).- Because the default constructor is
constexpr, staticunique_ptrs are initialized as part of static non-local initialization, before any dynamic non-local initialization begins. This makes it safe to use aunique_ptrin a constructor of any static object. - (since C++17) There is no class template argument deduction from pointer type because it is impossible to distinguish a pointer obtained from array and non-array forms of
new.
π Example π
// Run this code
#include <iostream>
#include <memory>
struct Foo // object to manage
{
Foo() { std::cout << "Foo ctor\n"; }
Foo(const Foo&) { std::cout << "Foo copy ctor\n"; }
Foo(Foo&&) { std::cout << "Foo move ctor\n"; }
~Foo() { std::cout << "~Foo dtor\n"; }
};
struct D // deleter
{
D() {};
D(const D&) { std::cout << "D copy ctor\n"; }
D(D&) { std::cout << "D non-const copy ctor\n"; }
D(D&&) { std::cout << "D move ctor \n"; }
void operator()(Foo* p) const
{
std::cout << "D is deleting a Foo\n";
delete p;
};
};
int main()
{
std::cout << "Example constructor(1)...\n";
std::unique_ptr<Foo> up1; // up1 is empty
std::unique_ptr<Foo> up1b(nullptr); // up1b is empty
std::cout << "Example constructor(2)...\n";
{
std::unique_ptr<Foo> up2(new Foo); //up2 now owns a Foo
} // Foo deleted
std::cout << "Example constructor(3)...\n";
D d;
{ // deleter type is not a reference
std::unique_ptr<Foo, D> up3(new Foo, d); // deleter copied
}
{ // deleter type is a reference
std::unique_ptr<Foo, D&> up3b(new Foo, d); // up3b holds a reference to d
}
std::cout << "Example constructor(4)...\n";
{ // deleter is not a reference
std::unique_ptr<Foo, D> up4(new Foo, D()); // deleter moved
}
std::cout << "Example constructor(5)...\n";
{
std::unique_ptr<Foo> up5a(new Foo);
std::unique_ptr<Foo> up5b(std::move(up5a)); // ownership transfer
}
std::cout << "Example constructor(6)...\n";
{
std::unique_ptr<Foo, D> up6a(new Foo, d); // D is copied
std::unique_ptr<Foo, D> up6b(std::move(up6a)); // D is moved
std::unique_ptr<Foo, D&> up6c(new Foo, d); // D is a reference
std::unique_ptr<Foo, D> up6d(std::move(up6c)); // D is copied
}
#if (__cplusplus < 201703L)
std::cout << "Example constructor(7)...\n";
{
std::auto_ptr<Foo> up7a(new Foo);
std::unique_ptr<Foo> up7b(std::move(up7a)); // ownership transfer
}
#endif
std::cout << "Example array constructor...\n";
{
std::unique_ptr<Foo[]> up(new Foo[3]);
} // three Foo objects deleted
}
β¨ Output β¨
okay so here's exactly what it prints when you run it β every single line, no skips, no cap:
Example constructor(1)...
Example constructor(2)...
Foo ctor
~Foo dtor
Example constructor(3)...
Foo ctor
D copy ctor
D is deleting a Foo
~Foo dtor
Foo ctor
D is deleting a Foo
~Foo dtor
Example constructor(4)...
Foo ctor
D move ctor
D is deleting a Foo
~Foo dtor
Example constructor(5)...
Foo ctor
~Foo dtor
Example constructor(6)...
Foo ctor
D copy ctor
D move ctor
Foo ctor
D non-const copy ctor
D is deleting a Foo
~Foo dtor
D is deleting a Foo
~Foo dtor
Example constructor(7)...
Foo ctor
~Foo dtor
Example array constructor...
Foo ctor
Foo ctor
Foo ctor
~Foo dtor
~Foo dtor
~Foo dtor
π Defect reports π
okay so these behavior-changing defect reports got applied retroactively to previously published C++ standards β here's the full receipts, bestie:
- LWG 2118 Β· applied to C++11 β behavior as published: "Constructors of
unique_ptr<T[]>rejected qualification conversions." Correct behavior: Accept. - LWG 2520 Β· applied to C++11 β behavior as published: "
unique_ptr<T[]>was accidentally made non-constructible fromnullptr_t." Correct behavior: Made constructible. - LWG 2801 Β· applied to C++11 β behavior as published: "The default constructor was not constrained." Correct behavior: Constrained.
- LWG 2899 Β· applied to C++11 β behavior as published: "The move constructor was not constrained." Correct behavior: Constrained.
- LWG 2905 Β· applied to C++11 β behavior as published: "Constraint on the constructor from a pointer and a deleter was wrong." Correct behavior: Corrected.
- LWG 2944 Β· applied to C++11 β behavior as published: "Some preconditions were accidentally dropped by LWG 2905" Correct behavior: Restored.
that's a wrap on this manpage π footer tea: it's from cppreference.com, dated 2024.06.10 β keep slaying those smart pointers, bestie π β¨
π¦ where this page comes from
- nixpkgs unstable: stdman 2024.07.05
- opensuse-leap 16.0: stdman 2024.07.05-bp160.1.9 Β· MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms