unique_ptr管理动态数组必须指定删除器,否则析构时调用delete而非delete[]导致未定义行为;正确方式为std::unique_ptr或自定义删除器;不支持get()后手动delete[],release()后须用delete[]释放;make_unique(n)仅支持默认初始化。

unique_ptr管理动态数组必须指定删除器
直接用 std::unique_ptr<int></int> 接收 new int[10] 会导致未定义行为——析构时调用 delete 而非 delete[],内存没被正确释放,还可能踩内存。
正确做法是让 unique_ptr 知道它管的是数组,有两种等效写法:
-
std::unique_ptr<int> ptr(new int[5]);</int>—— 类型后加[],编译器自动选delete[] -
std::unique_ptr<int void> ptr(new int[5], [](int* p) { delete[] p; });</int>—— 显式传自定义删除器
第一种更简洁常用;第二种适合需要额外清理逻辑(比如日志、计数)的场景。
不能用 get() 返回的指针做算术运算再 delete[]
unique_ptr::get() 只返回裸指针,不改变所有权,也不影响析构行为。有人误以为“我拿到指针了,自己 delete[] 就行”,这是危险的:
- 忘记删 → 内存泄漏
- 重复删(比如
ptr后续仍被析构)→ 二次释放崩溃 - 用
delete而非delete[]→ 未定义行为
所有资源释放必须交给 unique_ptr 自己完成。如果真要访问某元素,直接用 ptr[i](支持下标访问),或 ptr.get() + offset 仅用于只读计算,绝不要拿去 delete。
数组 unique_ptr 不支持 release() 后手动 delete[]?其实支持,但要小心类型匹配
release() 会交出裸指针并置空智能指针,此时你得自己负责释放。关键点在于:交出来的指针类型必须和当初 new 的一致。
- 若声明为
std::unique_ptr<int></int>,release()返回的是int*,但语义上它指向数组首地址,**必须用delete[]** - 不能因为类型是
int*就用delete,否则出问题 - 示例:
auto ptr = std::make_unique<int>(3); int* raw = ptr.release(); // 此时 ptr 为空 delete[] raw; // ✅ 正确</int>
make_unique 对数组的支持有限,C++14 才有,且不能带参数初始化
std::make_unique<t>(N)</t> 在 C++14 引入,能安全构造数组版 unique_ptr,但只能做默认初始化(即 int[N] 中元素为零值):
-
auto p = std::make_unique<int>(10);</int>→ 全部初始化为 0 -
std::make_unique<int>(10, 42)</int>❌ 编译失败 —— 不支持带初始值的数组构造 - 如果需要自定义初始化(比如全设为 42),只能手写
new int[10]{}+ 初始化列表,或改用std::vector
别为了省几行代码绕开 make_unique 就用裸 new,除非你明确需要控制初始化逻辑。
最易忽略的一点:数组版 unique_ptr 的类型签名(如 unique_ptr<int></int>)不是语法糖,它是独立特化类型,不能隐式转成 unique_ptr<int></int>,也不能和后者混用——编译器会立刻报错,这反而是好事,能拦住多数误用。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











