命名空间
变体
操作

std::unique_ptr

来自 cppreference.com
< cpp‎ | memory
 
 
实用程序库
语言支持
类型支持 (基本类型,RTTI)
库特性测试宏 (C++20)
动态内存管理
程序实用程序
协程支持 (C++20)
可变参数函数
调试支持
(C++26)
三路比较
(C++20)
(C++20)(C++20)(C++20)
(C++20)(C++20)(C++20)
通用实用程序
日期和时间
函数对象
格式化库 (C++20)
(C++11)
关系运算符 (C++20 中已弃用)
整数比较函数
(C++20)(C++20)(C++20)   
(C++20)
交换类型操作
(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)



 
 
在头文件 <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 也可以选择不拥有任何对象,在这种情况下,它被称为

std::unique_ptr 有两个版本

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

该类满足 MoveConstructibleMoveAssignable 的要求,但不满足 CopyConstructibleCopyAssignable 的要求。

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

内容

[编辑] 备注

只有非 const unique_ptr 可以将托管对象的拥有权转移到另一个 unique_ptr。如果对象的生存期由 const std::unique_ptr 管理,它将被限制在创建该指针的范围。

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

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

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

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

std::shared_ptr 不同,std::unique_ptr 可以通过任何满足 NullablePointer 的自定义句柄类型来管理对象。例如,这允许通过提供一个 Deleter 来管理位于共享内存中的对象,该 Deleter 定义了 typedef boost::offset_ptr pointer; 或其他 奇特指针

特性测试 Std 特性
__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>
 
// helper class for runtime polymorphism demo below
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"; }
};
 
// a function consuming a unique_ptr can take it by value or by rvalue reference
std::unique_ptr<D> pass_through(std::unique_ptr<D> p)
{
    p->bar();
    return p;
}
 
// helper function for the custom deleter demo below
void close_file(std::FILE* fp)
{
    std::fclose(fp);
}
 
// unique_ptr-based linked list demo
struct List
{
    struct Node
    {
        int data;
        std::unique_ptr<Node> next;
    };
 
    std::unique_ptr<Node> head;
 
    ~List()
    {
        // destroy list nodes sequentially in a loop, the default destructor
        // would have invoked its `next`'s destructor recursively, which would
        // cause stack overflow for sufficiently large lists.
        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) Unique ownership semantics demo\n";
    {
        // Create a (uniquely owned) resource
        std::unique_ptr<D> p = std::make_unique<D>();
 
        // Transfer ownership to `pass_through`,
        // which in turn transfers ownership back through the return value
        std::unique_ptr<D> q = pass_through(std::move(p));
 
        // p is now in a moved-from 'empty' state, equal to nullptr
        assert(!p);
    }
 
    std::cout << "\n" "2) Runtime polymorphism demo\n";
    {
        // Create a derived resource and point to it via base type
        std::unique_ptr<B> p = std::make_unique<D>();
 
        // Dynamic dispatch works as expected
        p->bar();
    }
 
    std::cout << "\n" "3) Custom deleter demo\n";
    std::ofstream("demo.txt") << 'x'; // prepare the file to read
    {
        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()` called here (if `fp` is not null)
 
    std::cout << "\n" "4) Custom lambda-expression deleter and exception safety demo\n";
    try
    {
        std::unique_ptr<D, void(*)(D*)> p(new D, [](D* ptr)
        {
            std::cout << "destroying from a custom deleter...\n";
            delete ptr;
        });
 
        throw std::runtime_error(""); // `p` would leak here if it were a plain pointer
    }
    catch (const std::exception&)
    {
        std::cout << "Caught exception\n";
    }
 
    std::cout << "\n" "5) Array form of unique_ptr demo\n";
    {
        std::unique_ptr<D[]> p(new D[3]);
    } // `D::~D()` is called 3 times
 
    std::cout << "\n" "6) Linked list demo\n";
    {
        List wall;
        const int enough{1'000'000};
        for (int beer = 0; beer != enough; ++beer)
            wall.push(beer);
 
        std::cout.imbue(std::locale("en_US.UTF-8"));
        std::cout << enough << " bottles of beer on the wall...\n";
    } // destroys all the beers
}

可能的输出

1) Unique ownership semantics demo
D::D
D::bar
D::~D
 
2) Runtime polymorphism demo
D::D
D::bar
D::~D
 
3) Custom deleter demo
x
 
4) Custom lambda-expression deleter and exception safety demo
D::D
destroying from a custom deleter...
D::~D
Caught exception
 
5) Array form of unique_ptr demo
D::D
D::D
D::D
D::~D
D::~D
D::~D
 
6) Linked list demo
1,000,000 bottles of beer on the wall...

[编辑] 参见

具有共享对象拥有权语义的智能指针
(类模板) [编辑]
(C++11)
对由 std::shared_ptr 管理的对象的弱引用
(类模板) [编辑]