std::unique_ptr<T,Deleter>::unique_ptr
来自cppreference.com
< cpp | memory | unique ptr
unique_ptr<T> 主模板的成员 |
||
constexpr unique_ptr() noexcept; constexpr unique_ptr( std::nullptr_t ) noexcept; |
(1) | |
explicit unique_ptr( pointer p ) noexcept; |
(2) | (C++23 起为 constexpr) |
unique_ptr( pointer p, /* 见下文 */ d1 ) noexcept; |
(3) | (C++23 起为 constexpr) |
unique_ptr( pointer p, /* 见下文 */ d2 ) noexcept; |
(4) | (C++23 起为 constexpr) |
unique_ptr( unique_ptr&& u ) noexcept; |
(5) | (C++23 起为 constexpr) |
template< class U, class E > unique_ptr( unique_ptr<U, E>&& u ) noexcept; |
(6) | (C++23 起为 constexpr) |
unique_ptr( const unique_ptr& ) = delete; |
(7) | |
template< class U > unique_ptr( std::auto_ptr<U>&& u ) noexcept; |
(8) | (C++17 中移除) |
unique_ptr<T[]> 数组版本特化的成员 |
||
constexpr unique_ptr() noexcept; constexpr unique_ptr( std::nullptr_t ) noexcept; |
(1) | |
template< class U > explicit unique_ptr( U p ) noexcept; |
(2) | (C++23 起为 constexpr) |
template< class U > unique_ptr( U p, /* 见下文 */ d1 ) noexcept; |
(3) | (C++23 起为 constexpr) |
template< class U > unique_ptr( U p, /* 见下文 */ d2 ) noexcept; |
(4) | (C++23 起为 constexpr) |
unique_ptr( unique_ptr&& u ) noexcept; |
(5) | (C++23 起为 constexpr) |
template< class U, class E > unique_ptr( unique_ptr<U, E>&& u ) noexcept; |
(6) | (C++23 起为 constexpr) |
unique_ptr( const unique_ptr& ) = delete; |
(7) | |
1) 构造不拥有对象的
std::unique_ptr
。值初始化存储的指针和存储的删除器。要求 Deleter
可默认构造 (DefaultConstructible) 且构造不抛异常。这些重载只有在 std::is_default_constructible<Deleter>::value 为 true 且 Deleter 不是指针类型时才会参与重载决议。2) 构造拥有 p 的
std::unique_ptr
,以 p 初始化存储的指针,并值初始化存储的删除器。要求 Deleter
可默认构造 (DefaultConstructible) 且构造不抛异常。这些重载只有在 std::is_default_constructible<Deleter>::value 为 true 且 Deleter 不是指针类型时才会参与重载决议。
类模板实参推导不选择此构造函数。 |
(C++17 起) |
3,4) 构造拥有 p 的
std::unique_ptr
对象,以 p 初始化存储的指针,并按下列方式初始化删除器 D
(依赖于 D
是否为引用类型)。a) 若
D
是非引用类型 A,则签名是:
unique_ptr(pointer p, const A& d) noexcept; |
(1) | (要求 Deleter 为不抛出可复制构造 (CopyConstructible) ) |
unique_ptr(pointer p, A&& d) noexcept; |
(2) | (要求 Deleter 为不抛出可移动构造 (MoveConstructible) ) |
b) 若
D
是左值引用类型 A&,则签名是:
unique_ptr(pointer p, A& d) noexcept; |
(1) | |
unique_ptr(pointer p, A&& d) = delete; |
(2) | |
c) 若
D
是左值引用类型 const A&,则签名是:
unique_ptr(pointer p, const A& d) noexcept; |
(1) | |
unique_ptr(pointer p, const A&& d) = delete; |
(2) | |
所有情况下删除器从 std::forward<decltype(d)>(d) 初始化。这些重载只有在 std::is_constructible<D, decltype(d)>::value 为 true 时才会参与重载决议。
类模板实参推导不选择这两个构造函数。 |
(C++17 起) |
2-4) 数组特化中表现同主模板中接收一个指针参数的构造函数,此外除非下列之一为真,否则它们不参与重载决议:
-
U
与pointer
为同一类型,或 -
U
为 std::nullptr_t,或 -
pointer
与element_type*
为同一类型且U
为指针类型V*
,满足V(*)[]
可隐式转换为element_type(*)[]
。
5) 通过从 u 转移所有权给 *this 构造
unique_ptr
并存储空指针于 u。此构造函数仅若 std::is_move_constructible<Deleter>::value 为 true 才参与重载决议。若 Deleter
不是引用类型,则要求它为不抛出可移动构造 (MoveConstructible) (若 Deleter
是引用,则 get_deleter()
和 u.get_deleter()
在移动构造后引用相同值)。6) 通过从 u 转移所有权给 *this 构造
unique_ptr
,其中 u 以指定的删除器(E
)构造。它依赖于 E
是否为引用类型,如下:a) 若
E
是引用类型,则从 u 的删除器复制构造此删除器(要求此构造不抛出)b) 若
E
不是引用类型,则从 u 的删除器移动构造此删除器(要求此构造不抛出) 此构造函数仅若下列皆为真才参与重载决议:
a) unique_ptr<U, E>::pointer 可隐式转换为
pointer
b) U 不是数组类型
c)
Deleter
是引用类型且 E
与 D
为同一类型,或 Deleter
不是引用类型且 E
可隐式转换为 D
6) 数组特化中,表现同在主模板中的版本,但它仅若下列皆为真才会参与重载决议
-
U
是数组类型 -
pointer
与element_type*
是同一类型 - unique_ptr<U,E>::pointer 与 unique_ptr<U,E>::element_type* 是同一类型
- unique_ptr<U,E>::element_type(*)[] 可转换为
element_type(*)[]
-
Deleter
是引用类型且E
与Deleter
是同一类型,或Deleter
非引用类型且E
可隐式转换为Deleter
。
7) 复制构造函数被显式弃置。
8) 构造
unique_ptr
,其中以 u.release() 初始化存储的指针,并值初始化存储的删除器。此构造函数仅若 U*
可隐式转换为 T*
且 Deleter
与 std::default_delete<T>
为同一类型才参与重载决议。参数
p | - | 指向要管理的对象的指针 |
d1, d2 | - | 用于销毁对象的删除器 |
u | - | 获取所有权来源的智能指针 |
注解
使用 std::make_unique<T> 是更好的做法,可取代与 new 一起使用的重载 (2)。 |
(C++14 起) |
std::unique_ptr<Derived> 通过重载 (6) 可隐式转换为 std::unique_ptr<Base>(因为被管理指针和 std::default_delete 都可隐式转换)。
因为默认构造函数是 constexpr,故静态的 unique_ptr
在任何动态初始化之前,作为静态非局部初始化的一部分初始化。这使得在任何静态对象的构造函数中使用 unique_ptr
都是安全的。
无源自指针类型的类模板实参推导,因为不可能区分从 |
(C++17 起) |
示例
运行此代码
#include <iostream> #include <memory> struct Foo // 要管理的对象 { Foo() { std::cout << "Foo 构造\n"; } Foo(const Foo&) { std::cout << "Foo 复制构造\n"; } Foo(Foo&&) { std::cout << "Foo 移动构造\n"; } ~Foo() { std::cout << "~Foo 析构\n"; } }; struct D // 删除器 { D() {}; D(const D&) { std::cout << "D 复制构造\n"; } D(D&) { std::cout << "D 非 const 复制构造\n";} D(D&&) { std::cout << "D 移动构造\n"; } void operator()(Foo* p) const { std::cout << "用 D 删除 Foo\n"; delete p; }; }; int main() { std::cout << "构造函数示例 (1)...\n"; std::unique_ptr<Foo> up1; // up1 为空 std::unique_ptr<Foo> up1b(nullptr); // up1b 为空 std::cout << "构造函数示例 (2)...\n"; { std::unique_ptr<Foo> up2(new Foo); // up2 现在占有 Foo } // Foo 被删除 std::cout << "构造函数示例 (3)...\n"; D d; { // 删除器类型不是引用 std::unique_ptr<Foo, D> up3(new Foo, d); // 复制删除器 } { // 删除器类型是引用 std::unique_ptr<Foo, D&> up3b(new Foo, d); // up3b 保有到 d 的引用 } std::cout << "构造函数示例 (4)...\n"; { // 删除器不是引用 std::unique_ptr<Foo, D> up4(new Foo, D()); // 移动删除器 } std::cout << "构造函数示例 (5)...\n"; { std::unique_ptr<Foo> up5a(new Foo); std::unique_ptr<Foo> up5b(std::move(up5a)); // 所有权转移 } std::cout << "构造函数示例 (6)...\n"; { std::unique_ptr<Foo, D> up6a(new Foo, d); // 复制 D std::unique_ptr<Foo, D> up6b(std::move(up6a)); // 移动 D std::unique_ptr<Foo, D&> up6c(new Foo, d); // D 是引用 std::unique_ptr<Foo, D> up6d(std::move(up6c)); // 复制 D } #if (__cplusplus < 201703L) std::cout << "构造函数示例 (7)...\n"; { std::auto_ptr<Foo> up7a(new Foo); std::unique_ptr<Foo> up7b(std::move(up7a)); // 所有权转移 } #endif std::cout << "数组构造函数示例...\n"; { std::unique_ptr<Foo[]> up(new Foo[3]); } // 删除三个 Foo 对象 }
输出:
构造函数示例 (1)... 构造函数示例 (2)... Foo 构造 ~Foo 析构 构造函数示例 (3)... Foo 构造 D 复制构造 用 D 删除 Foo ~Foo 析构 Foo 构造 用 D 删除 Foo ~Foo 析构 构造函数示例 (4)... Foo 构造 D 移动构造 用 D 删除 Foo ~Foo 析构 构造函数示例 (5)... Foo 构造 ~Foo 析构 构造函数示例 (6)... Foo 构造 D 复制构造 D 移动构造 Foo 构造 D 非 const 复制构造 用 D 删除 Foo ~Foo 析构 用 D 删除 Foo ~Foo 析构 构造函数示例 (7)... Foo 构造 ~Foo 析构 数组构造函数示例... Foo 构造 Foo 构造 Foo 构造 ~Foo 析构 ~Foo 析构 ~Foo 析构
缺陷报告
下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。
缺陷报告 | 应用于 | 出版时的行为 | 正确行为 |
---|---|---|---|
LWG 2118 | C++11 | unique_ptr<T[]> 的构造函数拒绝限定转换
|
接受 |
LWG 2520 | C++11 | unique_ptr<T[]> 被意外地设为不可从 nullptr_t 构造
|
使之可构造 |
LWG 2801 | C++11 | 默认构造函数未受约束 | 已约束 |
LWG 2899 | C++11 | 移动构造函数未受约束 | 已约束 |
LWG 2905 | C++11 | 来自指针和删除器的构造函数上的约束错误 | 更正 |
LWG 2944 | C++11 | 某些前条件被 LWG 2905 意外丢弃 | 恢复 |