安全释放 int** 必须按分配逆序:先逐行 delete[] arr[i],再 delete[] arr;否则导致悬空指针、内存泄漏或崩溃。推荐用 std::vector 替代裸指针。

释放 int** 前必须确认它是怎么分配的
直接调用 delete[] arr 不等于安全释放——它只释放了行指针数组本身,而每行指向的内存(arr[i])还挂在堆上。野指针、悬空指针、内存泄漏全由此而来。
安全释放的前提是:你清楚这个 int** 是用「二级指针方式」分配的,即:
-
arr = new int*[rows]分配行指针数组 - 再对每个
i执行arr[i] = new int[cols]分配列空间
如果不是这种两层 new,比如是 int* arr = new int[rows * cols] 一维模拟二维,那用双重 delete[] 就会崩溃。
delete[] 的顺序不能颠倒:先子后父
释放必须严格按分配的逆序:先逐行 delete[] arr[i],再 delete[] arr。反过来会导致未定义行为——delete[] arr 后,arr[i] 变成悬空指针,再解引用或释放就段错误。
立即学习“C++免费学习笔记(深入)”;
典型正确写法:
for (int i = 0; i < rows; ++i) {
delete[] arr[i]; // 释放第 i 行
}
delete[] arr; // 释放行指针数组常见错误:
- 漏掉某一行的
delete[] arr[i]→ 内存泄漏 - 写成
delete arr[i](少[])→ 仅释放首元素,其余未回收 - 释放后仍访问
arr[i][j]或再次delete[] arr[i]→ 悬空指针二次释放
释放后建议置空,尤其在多处可能访问时
释放完不置空,后续若误判指针状态(比如检查 if (arr)),仍可能解引用悬空地址。虽然 C++ 不强制要求,但在函数内局部使用、或作为类成员时,加一句 arr = nullptr 能避免很多调试噩梦。
推荐写法:
for (int i = 0; i < rows; ++i) {
delete[] arr[i];
arr[i] = nullptr; // 防止重复释放或误用
}
delete[] arr;
arr = nullptr;注意:arr[i] = nullptr 只在 arr 未被 delete[] 前有效;一旦 delete[] arr 完成,arr 本身也不该再读写。
更安全的替代方案:优先考虑 std::vector<:vector>></:vector> 或一维向量
手写 int** + 手动 delete[] 天然容易出错。现代 C++ 中,除非有明确性能/接口约束(如对接 C API),否则应避开裸二级指针。
两种更稳的选择:
-
std::vector<:vector>> mat(rows, std::vector<int>(cols));</int></:vector>—— 语义清晰,自动管理,但内存不连续 -
std::vector<int> data(rows * cols); auto at = [&](int i, int j) { return &data[i * cols + j]; };</int>—— 内存连续、缓存友好,且无手动释放负担
真正需要裸指针的场景极少;多数所谓“性能关键”,其实是过早优化——先用 vector 写对,再用 perf 看瓶颈在哪。


















