delete[]必须配对new[],否则行为未定义;用new[]分配的数组必须用delete[]释放,用new分配的单个对象才用delete,混用会导致内存泄漏、堆损坏或程序崩溃。

delete[] 必须配对 new[],否则行为未定义
用 new[] 分配的数组,必须用 delete[] 释放;用 new 分配的单个对象,才用 delete。混用会导致内存泄漏、堆损坏或程序崩溃——这不是“可能出错”,而是标准明确定义为“未定义行为”。
常见错误现象:
- 程序在某些平台看似正常,换编译器或开启 ASan 就直接 abort
- 析构函数只调用一次(该调多次却没调),对象内部资源泄漏
- delete 后访问数组元素仍不报错,但后续 malloc 失败或数据错乱
-
int* p = new int[10]; delete p;❌ 错误:应为delete[] p; -
int* p = new int; delete[] p;❌ 同样未定义,且可能跳过析构 - 即使数组元素是
int这类 POD 类型,也必须用delete[]—— 编译器需要知道元素个数来正确清理(尤其对带析构函数的类型)
vector 替代 raw array 是更安全的选择
手动管理 new[]/delete[] 容易漏掉释放、重复释放、或异常路径下未释放。现代 C++ 中,99% 的场景应该用 std::vector 或 std::array。
使用场景:
- 需要动态大小 + 随机访问 + 自动内存管理 → std::vector
- 固定大小 + 栈上分配 → std::array
- 确实要裸指针(如对接 C API、高性能循环内避免构造开销)→ 才考虑 new[]
-
std::vector<int> v(10);</int>—— 不用手动delete,离开作用域自动释放 -
v.data()可获取底层int*指针,兼容 C 接口 - 如果必须用裸数组,建议封装成 RAII 类(如自定义
ArrayHolder),而非裸写new[]/delete[]
delete[] 后立即置空指针,避免悬垂指针二次释放
delete[] p; 不会自动把 p 设为 nullptr,此时 p 成为悬垂指针。若后续又执行 delete[] p;,就是典型的 double-delete,极大概率 crash。
- 养成习惯:
delete[] p; p = nullptr; - 检查是否为空再释放:
if (p) { delete[] p; p = nullptr; }(虽非必须,但可防御部分逻辑错误) - 注意:
delete[] nullptr是安全的,C++ 标准允许,但不解决悬垂问题本身
ASan 和 UBSan 能抓到多数 delete/delete[] 混用问题
仅靠肉眼 review 很难发现 delete / delete[] 不匹配。启用编译器检测工具能提前暴露问题:
- Clang/GCC 加
-fsanitize=address,undefined编译运行,混用会直接报heap-use-after-free或undefined behavior: mismatched new[]/delete - MSVC 可用
/fsanitize=address(VS2019+)或 CRT 调试堆(_CrtDumpMemoryLeaks())辅助定位 - 注意:Release 模式下这些检查通常被关闭,所以务必在 CI 或开发阶段启用
真正麻烦的不是语法写错,而是有人觉得“int 数组不用 delete[] 也行”,或者把 vector::data() 返回的指针拿去 delete[] —— 这类错误不会编译报错,但会在某个随机时刻让程序倒下。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











