std::unique_ptr 是管理动态数组的正确方式,因普通 std::unique_ptr 析构时调用 delete 而非 delete[],导致未定义行为;推荐使用 std::make_unique(10) 且需注意其不存长度、不支持迭代器、仅可移动不可复制。

用 std::unique_ptr<t></t> 是最直接、最安全的自动清理方式,不需要手动调用 delete[],也不会因异常跳过析构导致泄漏。
为什么不能用 std::unique_ptr<t></t> 管理数组
这是最容易踩的坑:类型不匹配会导致未定义行为。即使代码能编译通过,std::unique_ptr<int></int> 析构时调用的是 delete,而非 delete[],对数组首地址执行 delete 会跳过除第一个元素外所有对象的析构函数(如果是类类型),且违反 C++ 标准。
-
std::unique_ptr<int> p(new int[10]);</int>—— 错误!析构时调用delete p.get() -
std::unique_ptr<int> p(new int[10]);</int>—— 正确!析构时调用delete[] p.get() - 更推荐用
std::make_unique<int>(10)</int>,它直接生成int[]特化版本,且异常安全
std::unique_ptr<t></t> 的实际用法和限制
它支持下标访问、移动语义,但不支持 begin()/end()、不提供大小信息,也不能隐式转为裸指针数组。
- 赋值和访问:直接用
ptr[i],和原生数组一致 - 获取裸指针:用
ptr.get(),返回T*,可用于传参给 C 接口 - 无法获取长度:
std::unique_ptr不存储 size,需额外变量保存 - 不能复制,只能移动:
auto p2 = std::move(p1);后p1为空
需要自定义删除器的特殊情况
当数组不是用 new[] 分配(比如用 malloc 或 mmap),或需附加清理逻辑(如日志、资源同步)时,必须显式传入删除器。
- 用
malloc分配的数组:删除器必须是free,且模板参数要匹配指针类型 - 示例:
std::unique_ptr<int void> ptr(static_cast<int>(malloc(10 * sizeof(int))), free);</int></int> - Lambda 删除器需注意类型推导:用
decltype捕获或显式声明模板参数,否则编译失败 - 删除器对象本身不能抛异常,否则在析构中触发异常会调用
std::terminate
真正关键的一点是:只要数组元素是类类型,就必须确保析构函数被逐个调用;而只有 std::unique_ptr<t></t> 或带 delete[] 删除器的智能指针才能做到这点——裸指针、std::unique_ptr<t></t>、甚至没配对删除器的 std::shared_ptr 都不行。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











