一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

C++怎样使用std::unique_ptr管理动态分配的数组

时间:2026-06-23 08:28:47 编辑:袖梨 来源:一聚教程网

<p>std::unique_ptr<T[]> 必须显式指定数组类型,否则 new int[10] 会调用 delete 而非 delete[],导致未定义行为;它支持 operator[] 但禁用 operator* 和 operator->,构造需 new T[N] 或 C++14+ 的 make_unique<N>()。</p>

std::unique_ptr 必须显式指定数组类型

直接用 std::unique_ptr<int></int> 管理 new int[10] 会导致析构时调用 delete 而非 delete[],引发未定义行为——这是最常踩的坑。

正确做法是使用带方括号的特化类型:std::unique_ptr<int></int>。编译器据此选择 delete[],并禁用 operator*operator->(因为数组不支持解引用单个对象)。

  • std::unique_ptr<int></int> 支持 operator[],可像原生数组一样访问元素
  • 不能写成 std::unique_ptr<int></int> —— 编译器不接受带长度的数组类型作为模板参数
  • 构造时只能传入 new int[N],不能传入栈数组地址或空指针(除非显式初始化为 nullptr

初始化方式:用 new T[N],别用 make_unique(C++14 之前不支持数组)

std::make_unique 在 C++14 才开始支持数组,且语法和语义与标量不同:它会自动推导 T[] 类型,但不接受自定义大小参数(即不能写 make_unique<int>(10)</int>)。

因此在 C++11 或需要明确控制内存分配逻辑时,必须手写 new

立即学习“C++免费学习笔记(深入)”;

std::unique_ptr<int[]> ptr(new int[5]);

C++14+ 可安全使用:

auto ptr = std::make_unique<int[]>(5); // 分配 5 个默认初始化的 int
  • make_unique<int>(N)</int> 总是值初始化(int() → 0),而 new int[N] 是默认初始化(值未定义)
  • 若需保留未初始化行为(如后续 memcpy),只能用 new + std::unique_ptr<t></t>
  • 无法用 make_unique 构造非默认可构造类型的数组(如 std::unique_ptr<:string></:string> 会调用每个元素的默认构造函数)

移动语义可用,但拷贝被禁用

std::unique_ptr<t></t> 遵循唯一所有权原则,拷贝构造和赋值运算符被显式删除;移动则完全支持,且移动后源对象变为 nullptr

  • 移动后原指针失效,再次访问 ptr.get() 返回 nullptr,调用 operator[] 会触发空指针解引用
  • 可安全用于容器:例如 std::vector<:unique_ptr>></:unique_ptr> 存储变长数组
  • 函数返回时推荐直接移动: return std::move(ptr);(虽然命名变量返回时通常自动移动,但显式写出更清晰)

释放时机与资源泄漏风险点

数组版 unique_ptr 在超出作用域、被移动、或显式调用 reset() 时自动调用 delete[],但有三个容易忽略的边界情况:

  • 若在构造时抛出异常(比如 new 失败),unique_ptr 不会持有任何资源,无需担心泄漏
  • 若用 release() 交出裸指针,必须手动确保后续调用 delete[],否则泄漏
  • 不能混用 get() 返回的指针和其它智能指针(如再包一层 shared_ptr),否则双重释放

真正难排查的是跨 DLL 边界传递:若 new 和 delete[] 不在同一个模块(尤其 Windows 上不同 CRT 实例),即使类型匹配也会崩溃。这时要么统一用 make_unique(保证分配/释放同源),要么改用 std::vector

热门栏目