命名空间
变体
操作

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

来自 cppreference.cn
< cpp‎ | 内存‎ | unique ptr
 
 
内存管理库
(仅作说明*)
未初始化内存算法
(C++17)
(C++17)
(C++17)
受约束的未初始化
内存算法
C 库

分配器
内存资源
垃圾回收支持
(C++11)(直到 C++23)
(C++11)(直到 C++23)
(C++11)(直到 C++23)
(C++11)(直到 C++23)
(C++11)(直到 C++23)
(C++11)(直到 C++23)
未初始化存储
(直到 C++20*)
(直到 C++20*)
显式生命周期管理
 
 
主模板 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。值初始化存储的指针和存储的删除器。要求 DeleterDefaultConstructible 且构造不抛出异常。这些重载仅当 std::is_default_constructible<Deleter>::valuetrueDeleter 不是指针类型时参与重载决议。
2) 构造一个拥有 pstd::unique_ptr,用 p 初始化存储的指针并值初始化存储的删除器。要求 DeleterDefaultConstructible 且构造不抛出异常。此重载仅当 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 是 nothrow-CopyConstructible)
unique_ptr(pointer p, A&& d) noexcept;
(2) (要求 Deleter 是 nothrow-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,并在 u 中存储空指针来构造一个 unique_ptr。此构造函数仅当 std::is_move_constructible<Deleter>::valuetrue 时才参与重载决议。如果 Deleter 不是引用类型,则要求它是 nothrow-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 是引用类型且 EDeleter 类型相同,或者 Deleter 不是引用类型且 E 可隐式转换为 Deleter
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) 复制构造函数被显式删除。
8) 构造一个 unique_ptr,其中存储的指针用 u.release() 初始化,存储的删除器值初始化。此构造函数仅当 U* 可隐式转换为 T*Deleterstd::default_delete<T> 类型相同时才参与重载决议。

目录

[编辑] 参数

p - 指向要管理的对象的指针
d1, d2 - 用于销毁对象的删除器
u - 另一个智能指针,从中获取所有权

[编辑] 注解

除了使用重载 (2) 和 new 之外,通常更好的做法是使用 std::make_unique<T>

(C++14 起)

std::unique_ptr<Derived> 可通过重载 (6) 隐式转换为 std::unique_ptr<Base>(因为管理的指针和 std::default_delete 都可隐式转换)。

由于默认构造函数是 constexpr,静态 unique_ptrs 在 静态非局部初始化 部分进行初始化,早于任何动态非局部初始化。这使得在任何静态对象的构造函数中使用 unique_ptr 都是安全的。

不支持从指针类型进行 类模板实参推导,因为无法区分从数组和非数组形式的 new 获取的指针。

(C++17 起)

[编辑] 示例

#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
}

输出

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 意外删除。 已恢复。