unique_ptr管理动态数组必须使用std::unique_ptr特化版本,否则析构时调用delete而非delete[]导致未定义行为;不支持operator*和operator->,仅支持下标访问和get()获取原始指针;推荐auto p = std::unique_ptr(new int[100]);,避免与vector误用。

unique_ptr 管理动态数组必须用特化版本
直接用 std::unique_ptr<t></t> 指向 new T[n] 是未定义行为,析构时调用的是 delete 而非 delete[],导致内存泄漏或崩溃。C++ 标准提供了数组特化:必须显式使用 std::unique_ptr<t></t>。
常见错误现象:unique_ptr<int> p(new int[5]);</int> 编译可能通过(尤其旧编译器),但运行时释放错误;Clang/GCC 在较新标准下会报 deleting array through pointer to incomplete type 类似警告。
- 正确写法:
std::unique_ptr<int> p(new int[5]);</int> - 不能写
std::unique_ptr<int>{new int[5]}</int>后再赋值给unique_ptr<int></int>变量——类型不匹配,编译失败 - 数组长度不参与类型系统,
unique_ptr<int></int>这种写法非法,只有T[]形式被特化支持
访问数组元素不能用 *p 或 ->
unique_ptr<t></t> 不提供 operator* 和 operator->,因为语义上它管理的是数组而非单个对象。试图写 *p 或 p->foo() 会编译失败。
使用场景:你需要随机访问或遍历,而不是解引用为单个对象。
- 用下标访问:
p[0] = 42;、int x = p[i]; - 获取原始指针做底层操作:
int* raw = p.get();(注意:仍需确保只用于读/写,不 delete) - 不能对
p.get()调用delete[]—— unique_ptr 已接管所有权
初始化和构造有严格限制
数组版 unique_ptr 不支持自定义 deleter 的隐式转换,也不接受裸指针以外的初始化方式(比如不能用 make_unique 的普通重载)。
性能影响:无额外开销,特化版本的 deleter 是 default_delete<t></t>,内联调用 delete[],和手写完全一致。
- 推荐初始化:
auto p = std::unique_ptr<int>(new int[100]);</int> - 错误写法:
std::make_unique<int>(100)</int>—— C++14 起才支持该重载,且它做的是值初始化(new int[100]{}),不是默认初始化;C++14 之前不可用 - 如需自定义 deleter(极少见),必须显式传入:
std::unique_ptr<int void>{new int[10], [](int* p) { delete[] p; }};</int>
与 vector 的取舍要看真实需求
很多人想用 unique_ptr<t></t> 是为了“轻量级数组”,但容易忽略边界管理责任仍在你手上:没有 size()、不能 resize、越界完全不检查。
兼容性影响:所有标准库容器和算法都更适配 std::vector;而 unique_ptr<t></t> 主要用于对接 C API 或极简堆数组场景(比如需要精确控制分配器、或封装 legacy 接口)。
- 需要动态长度 + 安全访问 + 迭代器 → 选
std::vector - 只需要一块连续内存 + 明确生命周期 + 零开销抽象 →
unique_ptr<t></t>合理 - 别为了“不用 vector”而用它——多一次
.size()调用不是性能瓶颈,忘了[]特化才是真坑
最常被忽略的一点:模板参数里的 [] 必须紧贴类型名,写成 unique_ptr<int></int>(带空格)虽部分编译器容忍,但不符合标准,某些模板元编程上下文会失败。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











