std::unique_ptr<T,Deleter>::unique_ptr

来自cppreference.com
< cpp‎ | memory‎ | unique ptr
 
 
工具库
通用工具
日期和时间
函数对象
格式化库 (C++20)
(C++11)
关系运算符 (C++20 中弃用)
整数比较函数
(C++20)(C++20)(C++20)
(C++20)
swap 与类型运算
(C++14)
(C++11)
(C++11)
(C++11)
(C++17)
常用词汇类型
(C++11)
(C++17)
(C++17)
(C++17)
(C++11)
(C++17)
(C++23)
初等字符串转换
(C++17)
(C++17)
 
动态内存管理
未初始化内存算法
受约束的未初始化内存算法
分配器
垃圾收集支持
(C++11)(C++23 前)
(C++11)(C++23 前)
(C++11)(C++23 前)
(C++11)(C++23 前)
(C++11)(C++23 前)
(C++11)(C++23 前)



 
 
主模板 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, /* see below */ d1 ) noexcept;
(3) (C++23 起为 constexpr)
unique_ptr( pointer p, /* see below */ 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)
template< class U >
unique_ptr( std::auto_ptr<U>&& u ) noexcept;
(7) (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, /* see below */ d1 ) noexcept;
(3) (C++23 起为 constexpr)
template<class U> unique_ptr( U p, /* see below */ 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)
1) 构造不占有对象的 std::unique_ptr 。值初始化存储的指针和存储的删除器。要求 Deleter 可默认构造 (DefaultConstructible) 且构造不抛异常。这些重载只有在 std::is_default_constructible<Deleter>::valuetrueDeleter 不是指针类型时才会参与重载决议。
2) 构造占有 p 的 std::unique_ptr ,以 p 初始化存储的指针,并值初始化存储的删除器。要求 Deleter 可默认构造 (DefaultConstructible) 且构造不抛异常。这些重载只有在 std::is_default_constructible<Deleter>::valuetrueDeleter 不是指针类型时才会参与重载决议。

类模板实参推导不选择此构造函数。

(C++17 起)
3-4) 构造占有 pstd::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)>::valuetrue 时才会参与重载决议。

类模板实参推导不选择这二个构造函数。

(C++17 起)
2-4) 数组特化中表现同初等模板中接收一个指针参数的构造函数,除了它们不另外参与重载决议,除非下列之一为真:
  • Upointer 为同一类型,或
  • Ustd::nullptr_t ,或
  • pointerelement_type* 为同一类型且 U 为指针类型 V* ,满足 V(*)[] 可隐式转换为 element_type(*)[]
5) 通过从 u 转移所有权给 *this 构造 unique_ptr 并存储空指针于 u 。此构造函数仅若 std::is_move_constructible<Deleter>::valuetrue 才参与重载决议。若 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 是引用类型且 ED 为同一类型,或 Deleter 不是引用类型且 E 可隐式转换为 D
6) 数组特化中,表现同在初等模板中的版本,除了它仅若下列皆为真才会参与重载决议
  • U 是数组类型
  • pointerelement_type* 是同一类型
  • unique_ptr<U,E>::pointerunique_ptr<U,E>::element_type* 是同一类型
  • unique_ptr<U,E>::element_type(*)[] 可转换为 element_type(*)[]
  • Deleter 是引用类型且 EDeleter 是同一类型,或 Deleter 非引用类型且 E 可隐式转换为 Deleter
7) 构造 unique_ptr ,其中以 u.release() 初始化存储的指针,并值初始化存储的删除器。此构造函数仅若 U* 可隐式转换为 T*Deleterstd::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 是安全的。

无源自指针类型的类模板实参推导,因为不可能辨别来自 new 的数组和非数组形式的指针。

(C++17 起)

示例

#include <iostream>
#include <memory>
 
struct Foo { // 要管理的对象
    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 { // 删除器
    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 为空
    std::unique_ptr<Foo> up1b(nullptr);  // up1b 为空
 
    std::cout << "Example constructor(2)...\n";
    {
        std::unique_ptr<Foo> up2(new Foo); // up2 现在占有 Foo
    } // Foo 被删除
 
    std::cout << "Example constructor(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 << "Example constructor(4)...\n";
    {  // 删除器不是引用
       std::unique_ptr<Foo, D> up4(new Foo, D()); // 移动删除器
    }
 
    std::cout << "Example constructor(5)...\n";
    {
       std::unique_ptr<Foo> up5a(new Foo);
       std::unique_ptr<Foo> up5b(std::move(up5a)); // 所有权转移
    }
 
    std::cout << "Example constructor(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 << "Example constructor(7)...\n";
    {
        std::auto_ptr<Foo> up7a(new Foo);
        std::unique_ptr<Foo> up7b(std::move(up7a)); // 所有权转移
    }
#endif
 
    std::cout << "Example array constructor...\n";
    {
        std::unique_ptr<Foo[]> up(new Foo[3]);
    } // 删除三个 Foo 对象
}

输出:

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

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 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 意外丢弃 恢复