new[]必须配对delete[],否则为未定义行为:delete会仅调用首元素析构函数并错误释放内存,delete[]则正确释放整个数组并调用各元素析构函数;应优先使用vector或unique_ptr等现代RAII方案。

delete[] 必须配对 new[],否则行为未定义
用 new[] 分配的数组,必须用 delete[] 释放,哪怕数组元素是内置类型(如 int、char)。用普通 delete 去释放 new[] 得到的指针,C++ 标准明确列为未定义行为——可能当场崩溃、内存泄漏、或看似正常但破坏堆管理结构。
常见错误现象:delete p;(p 是 new int[10] 返回的)在某些编译器/平台下不报错,但换环境就段错误;或者程序运行一段时间后 malloc 失败。
- 只有一种例外:用
new T[n]分配T为 trivially destructible 类型(如int、double、纯 POD 结构),且你**完全确定**后续不会换编译器或标准库,才可能“侥幸”不崩——但这不是正确写法,别赌 -
delete[]会调用每个元素的析构函数(如果存在),而delete只调用第一个元素的析构函数,然后释放内存块头信息——这正是出错根源
如何判断该用 delete 还是 delete[]
看分配时用了哪个操作符,而不是看变量声明形式。指针本身没有“数组属性”,它只是地址。关键在分配源头:
-
int* p = new int[100];→ 必须用delete[] p; -
int* p = new int(42);→ 必须用delete p; -
MyClass* arr = new MyClass[5];→ 必须用delete[] arr;(否则 5 个对象中只有第 1 个的析构函数被调用) - 即使写成
int arr[100];(栈上数组),也不能用delete[]或delete—— 栈内存自动回收,手动释放会崩溃
现代 C++ 中应优先避免裸 new/delete
手动管理数组内存极易出错,且无法异常安全。除非对接 C API 或有极特殊性能要求,否则直接用标准容器:
立即学习“C++免费学习笔记(深入)”;
- 动态大小数组 →
std::vector<t></t>:自动管理内存,支持移动语义,push_back、resize安全可靠 - 固定大小数组 →
std::array<t n></t>:栈上分配,零开销,无需delete - 需要裸指针接口 →
std::unique_ptr<t></t>:构造时用new T[n],析构自动调用delete[],不会忘也不会错
例如:auto p = std::make_unique<int>(100);</int>,作用域结束自动 delete[],连括号都不用写。
调试时如何发现 delete/delete[] 混用
这类错误很难静态检查,依赖运行时工具:
- Linux 下用
valgrind --tool=memcheck ./a.out,会明确报告 “Mismatched free() / delete / delete []” - macOS 使用 AddressSanitizer:
clang++ -fsanitize=address -g test.cpp && ./a.out,出错时打印详细堆栈和分配点 - MSVC 调试版运行时(Debug CRT)会在
delete/delete[]不匹配时触发断言,弹出对话框
注意:这些工具只在检测到越界访问或释放异常时才报,单纯 delete/delete[] 混用有时需配合特定标志(如 valgrind 的 --freelist-vol=0)才能稳定捕获。
最麻烦的是那种没立即崩溃、但悄悄破坏 malloc 元数据的情况——它可能让后续某次看似无关的 new 失败,排查起来要翻好几层调用栈。


















