必须手动释放每行:先 new int*[rows] 再循环 new int[cols],释放时须逆序先逐行 delete[] 再 delete[] 行指针,否则内存泄漏。

用 int** 分配不连续二维数组,必须手动释放每行
这是最直观但容易出错的方式:先用 new int*[rows] 分配行指针数组,再对每行调用 new int[cols]。内存块彼此独立,地址不连续,缓存不友好,但每行长度可不同。
常见错误是只调用一次 delete[] arr,漏掉逐行释放——这会导致严重内存泄漏。
- 释放顺序必须严格逆序:先遍历
for (int i = 0; i ,再 <code>delete[] arr - 若某行分配失败(如
new int[cols]抛异常),已分配的前面几行必须手动清理,否则泄漏 - 不能用
std::vector<:vector>></:vector>替代时才考虑此法,比如对接 C 接口或需精确控制每行布局
用单次 new 分配一维内存 + 指针偏移模拟二维,更高效也更安全
只调用一次 new int[rows * cols],内存连续,访问局部性好,且只需一次 delete[]。但想保持 arr[i][j] 语法,得额外建一个行指针数组指向各“行首”。
这个中间指针数组本身也要动态分配,但它很小(仅 rows * sizeof(int*) ),且生命周期与主数据绑定。
- 示例关键步骤:
int* data = new int[rows * cols]; int** arr = new int*[rows]; for (int i = 0; i - 释放时先
delete[] data,再delete[] arr;顺序反了会崩 - 若只读或只写固定尺寸矩阵,直接用
data[i * cols + j]更省事,避免多一层间接寻址
std::unique_ptr<int></int> 能管二维吗?不能直接管,但可以封装
std::unique_ptr 的数组特化版本(std::unique_ptr<t></t>)只支持一维连续内存。它不理解“二维”,也不会帮你建行指针数组。
你仍得自己处理二维逻辑,但可以用它托管底层数据,把裸 new/delete[] 替换掉。
- 推荐组合:
std::unique_ptr<int> data{new int[rows * cols]}; std::unique_ptr<int> arr{new int*[rows]};</int></int> - 这样两层都受 RAII 保护,即使中途异常,析构也会自动释放
- 别用
std::unique_ptr<int></int>—— 它只会调用delete,不是delete[],对指针数组本身释放就错了
三维及以上用 int*** 是陷阱,优先改用一维展开或 std::vector
三层指针(int***)看似对应三维数组,实际极易失控:分配要三层循环,释放要三层嵌套,任意一层失败都会导致前序资源无法回收;调试时看 ***p 几乎无法判断当前层级语义。
除非在极特殊场景(如 GPU 内存映射、硬件寄存器分页表),否则应规避。
- 通用替代方案:用一维数组 + 手动索引计算,如
data[i * rows * cols + j * cols + k] - 开发阶段优先用
std::vector<:vector>>></:vector>,虽然内存不连续,但安全、可调试、支持.size() - 性能敏感时,用
std::vector<int></int>加封装类提供at(i,j,k)接口,兼顾安全与效率
真正难的不是写出来,而是释放时机和顺序——多维动态数组的每一层分配都引入一个独立的生命周期,而 C++ 不会自动帮你串联它们。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











