std::unique_ptr 必须显式声明数组类型以调用 delete[],否则用 std::unique_ptr 管理 new t[n] 会导致未定义行为;推荐用 std::make_unique(n) 构造,支持零初始化需手动循环或改用 vector。

std::unique_ptr 和 std::unique_ptr 不能混用
直接用 std::unique_ptr<int></int> 管理 new int[10] 会调用 delete 而不是 delete[],导致未定义行为——这是最常踩的坑。必须显式声明数组类型:用 std::unique_ptr<int></int>,而不是 std::unique_ptr<int></int>。
原因在于 std::unique_ptr 的默认删除器是 std::default_delete<t></t>,它对非数组类型调用 delete,对 T[] 类型特化后才调用 delete[]。类型系统不帮你自动推导数组语义。
-
std::unique_ptr<int> ptr(new int[5]);</int>✅ 安全 -
std::unique_ptr<int> ptr(new int[5]);</int>❌ UB(即使编译通过) -
auto ptr = std::make_unique<int>(5);</int>✅ 推荐,且自动 zero-initialize -
auto ptr = std::make_unique<int>(5);</int>→ 分配单个 int,值为 5,不是数组
std::make_unique 是首选构造方式
std::make_unique 对数组支持良好,且避免裸 new,更安全。但注意:它只接受元素个数,不支持自定义初始化值(比如全填 42),也不能传 initializer_list。
-
auto arr = std::make_unique<int>(10);</int>→ 分配 10 个 int,默认初始化(int 为未定义值,除非是 static 或加{}) -
auto arr = std::make_unique<int>(10);</int>后可手动赋值:arr[0] = 1; - 想零初始化?写成
std::make_unique<int>(10)()</int>不合法;正确写法是std::make_unique<int>(10)</int>+ 循环,或改用std::vector - 不要写
std::make_unique<int>(new int[10])</int>—— 编译不过,make_unique不接受裸指针
访问数组元素和获取原始指针
std::unique_ptr<t></t> 支持 [] 运算符重载,但不提供 data() 成员函数(C++17 起才加入)。别依赖 get() + offset 手动算地址,容易越界。
- 安全访问:
ptr[i](i 必须在 [0, N) 范围内,无边界检查) - 获取原始指针:
ptr.get()返回T*,可用于传给 C API,如memcpy(dst, ptr.get(), n * sizeof(int)) - C++17 起可用
ptr.get()或直接ptr.get() + i,但ptr.data()更语义清晰(仅当有该成员时) - 不能写
ptr.release()[5]—— release 后所有权移交,原对象变空,再解引用是悬空指针
不能用 std::unique_ptr 做容器元素或传递给模板算法
很多标准库算法(如 std::sort、std::find)要求迭代器支持 operator+ 和 operator-,而 std::unique_ptr<t></t> 不是迭代器,也不隐式转成指针数组。它只是一个带删除器的智能指针包装器。
- 想排序?得用
std::sort(ptr.get(), ptr.get() + size),显式传入原始指针范围 - 不能把
std::unique_ptr<int></int>放进std::vector当元素(虽然语法允许,但几乎没意义) - 需要动态大小 + 算法支持?优先选
std::vector;unique_ptr<t></t>只适合固定大小、零拷贝、明确生命周期绑定的场景(如 C 接口返回的数组) - 多维数组?
std::unique_ptr<int></int>合法但难维护,不如std::vector<:vector>></:vector>或一维展平 + 手动索引
实际项目里,除非你对接的是要求 int* + 明确长度的 C 函数,并且确定生命周期完全由这个 unique_ptr 管理,否则多数时候 std::vector 更省心。数组版 unique_ptr 的价值恰恰在于“不自动做太多事”——它不管理大小、不提供容量接口、不支持插入,就是纯粹的 RAII 包装,这点容易被忽略。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











