必须用 delete[] 释放 new[] 分配的数组,否则行为未定义;推荐用 std::vector 或 std::unique_ptr 替代裸指针,确保构造/析构正确与自动内存管理。

new[] 分配数组必须用 delete[] 释放
用 new[] 动态分配数组时,编译器会在内存前额外存储数组长度(具体实现依赖编译器),delete[] 才能正确调用每个元素的析构函数并释放整块内存。如果错用 delete(不带方括号),行为未定义:可能崩溃、内存泄漏,或看似正常但破坏堆管理结构。
常见错误现象:
- 释放后程序在后续
new或malloc时崩溃(堆损坏) - 类对象只调用第一个元素的析构函数,其余对象资源未清理
- Valgrind 报告 “Mismatched free() / delete / delete[]”
实操建议:
- 始终成对使用:
new[]↔delete[],new↔delete - 避免裸指针管理:优先用
std::vector或std::unique_ptr - 若必须用裸指针,命名时加后缀提示,如
int* arr_ptr→int* arr_raw
std::vector 是更安全的动态数组替代方案
std::vector 内部自动管理堆内存,支持动态扩容、移动语义、异常安全,且无需手动 delete。它不是“替代语法糖”,而是解决动态数组生命周期问题的标准答案。
使用场景:
- 需要频繁增删末尾元素(
push_back/pop_back) - 不确定数组大小,但需随机访问(
operator[]或at()) - 跨函数传递动态数据(可移动、可拷贝、RAII 自动清理)
性能影响注意点:
- 默认构造不分配内存;
reserve()可预分配避免多次 realloc - 调用
shrink_to_fit()可尝试释放多余容量(非强制) - 若确定大小且永不改变,
std::array或栈数组更轻量
std::unique_ptr 适合需要定制删除逻辑的场景
当必须用裸数组但又想避免手动 delete[] 时,std::unique_ptr 是折中选择。它自动调用 delete[],且禁止拷贝(防止浅拷贝导致重复释放),支持自定义 deleter。
关键差异:
-
std::unique_ptr—— 构造时传入ptr(new int[10]); new[]结果 -
ptr[i]可直接访问,但不提供size()成员(需自行记录长度) - 不能用
std::make_unique初始化(C++14 起支持,但注意:C++17 前不支持初始化列表)(n)
容易踩的坑:
- 误写成
std::unique_ptr(单个对象)→ 释放时调用delete,导致未定义行为 - 忘记保存数组长度,后续遍历时越界
- 试图用
get()返回的裸指针长期持有,脱离unique_ptr生命周期管理
malloc/free 不适用于 C++ 类对象数组
malloc 只分配原始内存,不调用构造函数;free 不调用析构函数。对含非平凡构造/析构函数的类(如 std::string、自定义类),用 malloc 分配数组等于制造悬空对象——内存存在,但对象状态未初始化,后续访问必然出错。
错误示例:
MyClass* arr = static_cast<myclass>(malloc(10 * sizeof(MyClass))); arr[0].do_something(); // 未构造,this 指向垃圾内存,UB</myclass>
若真需底层控制(如 placement new 场景),必须显式调用:
-
new (ptr) MyClass()逐个构造 -
obj.~MyClass()逐个析构 - 最后
free(ptr)
这种写法复杂、易错,仅限极少数系统级编程需求;日常开发应彻底回避。
真正麻烦的从来不是“怎么分配”,而是“谁负责释放”和“对象是否被正确构造/析构”。裸 new[] 把这两件事全推给程序员,而现代 C++ 提供的工具已经足够覆盖绝大多数情况——漏掉一个 [],或记错长度,都可能让问题延迟到运行数小时后才暴露。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











