Namespaces
Variants

std:: unique_ptr

From cppreference.net
Memory management library
( exposition only* )
Allocators
Uninitialized memory algorithms
Constrained uninitialized memory algorithms
Memory resources
Uninitialized storage (until C++20)
( until C++20* )
( until C++20* )
( until C++20* )

Garbage collector support (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
定义于头文件 <memory>
template <

class T,
class Deleter = std:: default_delete < T >

> class unique_ptr ;
(1) (C++11 起)
template <

class T,
class Deleter

> class unique_ptr < T [ ] , Deleter > ;
(2) (C++11 起)

std::unique_ptr 是一种智能指针,它通过指针拥有(负责)并管理另一个对象,并在 unique_ptr 超出作用域时处置该对象。

当以下任一情况发生时,将使用关联的删除器处置该对象:

  • 管理的 unique_ptr 对象被销毁时。
  • 管理的 unique_ptr 对象通过 operator= reset() 被赋予另一个指针时。

对象通过调用 get_deleter ( ) ( ptr ) 被销毁,该操作使用可能由用户提供的删除器。默认删除器( std::default_delete )使用 delete 运算符,该运算符会销毁对象并释放内存。

一个 unique_ptr 也可以不拥有任何对象,这种情况下它被称为 的。

有两种版本的 unique_ptr

  1. 管理单个对象(例如使用 new 分配)。
  2. 管理动态分配的对象数组(例如使用 new [ ] 分配)。

该类满足 MoveConstructible MoveAssignable 的要求,但不满足 CopyConstructible CopyAssignable 的要求。

如果 T* 不是有效类型(例如 T 是引用类型),则实例化 std :: unique_ptr < T, Deleter > 定义的程序将是非良构的。

类型要求
-
Deleter 必须是 函数对象 或对 函数对象 的左值引用或对函数的左值引用,且可调用参数类型为 unique_ptr < T, Deleter > :: pointer

目录

注释

只有非 const 的 unique_ptr 能够将其管理的对象所有权转移给另一个 unique_ptr 。若对象的生命周期由 const std :: unique_ptr 管理,则该生命周期被限制在创建该指针的作用域内。

unique_ptr 通常用于管理对象的生命周期,包括:

  • 为处理具有动态生存期对象的类和函数提供异常安全性,保证在正常退出和异常退出时都能执行删除操作。
  • 将具有动态生命周期的唯一拥有对象的所有权传递给函数。
  • 从函数中获取具有动态生命周期的唯一拥有对象的所有权。
  • 作为移动感知容器中的元素类型,例如 std::vector ,这些容器持有指向动态分配对象的指针(例如需要多态行为时)。

unique_ptr 可以针对 不完整类型 T 进行构造,例如用于在 pImpl 惯用法 中作为句柄使用。如果使用默认删除器,则 T 必须在调用删除器的代码位置是完整类型,这发生在 unique_ptr 的析构函数、移动赋值运算符和 reset 成员函数中。(相比之下, std::shared_ptr 无法从指向不完整类型的原始指针构造,但可以在 T 不完整时被销毁)。请注意,如果 T 是类模板特化,将 unique_ptr 用作操作数(例如 ! p )时,由于 ADL 的要求,需要 T 的模板参数为完整类型。

如果 T 是某个基类 B 派生类 ,那么 unique_ptr < T > 可以 隐式转换 unique_ptr < B > 。转换后得到的 unique_ptr < B > 的默认删除器将使用针对 B operator delete ,这会导致 未定义行为 ,除非 B 的析构函数是 虚函数 。请注意 std::shared_ptr 的行为有所不同: std:: shared_ptr < B > 将使用针对类型 T operator delete ,即使 B 的析构函数不是 虚函数 ,所拥有的对象也能被正确删除。

std::shared_ptr 不同, unique_ptr 可以通过任何满足 NullablePointer 要求的自定义句柄类型来管理对象。例如,通过提供定义了 typedef boost::offset_ptr pointer; Deleter 或其他 fancy pointer ,可以实现对位于共享内存中对象的管理。

功能测试 标准 功能
__cpp_lib_constexpr_memory 202202L (C++23) constexpr std::unique_ptr

嵌套类型

类型 定义
pointer std:: remove_reference < Deleter > :: type :: pointer 若该类型存在,否则为 T* 。必须满足 NullablePointer
element_type T ,由此 unique_ptr 管理的对象类型
deleter_type Deleter ,函数对象或函数/函数对象的左值引用,将在析构函数中被调用

成员函数

构造新的 unique_ptr
(公开成员函数)
若存在被管理对象则销毁它
(公开成员函数)
赋值 unique_ptr
(公开成员函数)
修改器
返回指向被管理对象的指针并释放所有权
(公开成员函数)
替换被管理对象
(公开成员函数)
交换被管理对象
(公开成员函数)
观察器
返回指向被管理对象的指针
(公开成员函数)
返回用于销毁被管理对象的删除器
(公开成员函数)
检查是否有关联的被管理对象
(公开成员函数)
单对象版本, unique_ptr<T>
解引用指向被管理对象的指针
(公开成员函数)
数组版本, unique_ptr<T[]>
提供对被管理数组的索引访问
(公开成员函数)

非成员函数

创建管理新对象的唯一指针
(函数模板)
与另一个 unique_ptr 或与 nullptr 进行比较
(函数模板)
将托管指针的值输出到输出流
(函数模板)
特化 std::swap 算法
(函数模板)

辅助类

std::unique_ptr 的哈希支持
(类模板特化)

示例

#include <cassert>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <locale>
#include <memory>
#include <stdexcept>
// 用于下方运行时多态演示的辅助类
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"; }
};
// 消费 unique_ptr 的函数可以通过值或右值引用接收
std::unique_ptr<D> pass_through(std::unique_ptr<D> p)
{
    p->bar();
    return p;
}
// 用于自定义删除器演示的辅助函数
void close_file(std::FILE* fp)
{
    std::fclose(fp);
}
// 基于 unique_ptr 的链表演示
struct List
{
    struct Node
    {
        int data;
        std::unique_ptr<Node> next;
    };
    std::unique_ptr<Node> head;
    ~List()
    {
        // 在循环中顺序销毁链表节点,默认析构函数会递归调用其“next”的析构函数,
        // 对于足够大的链表会导致栈溢出。
        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) 独占所有权语义演示\n";
    {
        // 创建(独占拥有的)资源
        std::unique_ptr<D> p = std::make_unique<D>();
        // 将所有权转移给 “pass_through”,
        // 该函数通过返回值将所有权转移回来
        std::unique_ptr<D> q = pass_through(std::move(p));
        // “p” 现在处于已移动的“空”状态,等于 nullptr
        assert(!p);
    }
    std::cout << "\n" "2) 运行时多态演示\n";
    {
        // 创建派生资源并通过基类指针指向它
        std::unique_ptr<B> p = std::make_unique<D>();
        // 动态分派按预期工作
        p->bar();
    }
    std::cout << "\n" "3) 自定义删除器演示\n";
    std::ofstream("demo.txt") << 'x'; // 准备要读取的文件
    {
        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()”(如果 “fp” 不为空)
    std::cout << "\n" "4) 自定义 lambda 表达式删除器和异常安全演示\n";
    try
    {
        std::unique_ptr<D, void(*)(D*)> p(new D, [](D* ptr)
        {

缺陷报告

下列行为变更缺陷报告被追溯应用于先前发布的 C++ 标准。

缺陷报告 应用于 发布时的行为 正确行为
LWG 4144 C++11 T* 未要求构成有效类型 要求构成有效类型

参见

(C++11)
具有共享对象所有权语义的智能指针
(类模板)
(C++11)
对由 std::shared_ptr 管理的对象的弱引用
(类模板)
(C++26)
包含具有类值语义的动态分配对象的包装器
(类模板)
(C++17)
可容纳任何 CopyConstructible 类型实例的对象
(类)