C++ delete 和 delete[] 有什么区别?
在 C++ 中,delete 和 delete[] 都是用来释放动态分配的内存的操作符,但它们的使用场景和底层行为有着严格的区别。
核心的区别可以用一句话概括:delete 用于释放单个对象的内存,而 delete[] 用于释放对象数组的内存。
下面是详细的区别和原理解析:
1. 匹配规则
- 如果你用
new分配内存,必须用delete释放。 - 如果你用
new[]分配内存,必须用delete[]释放。
// 1. 单个对象
int* p1 = new int(10);
delete p1; // 正确
// 2. 数组对象
int* p2 = new int[10];
delete[] p2; // 正确
2. 底层执行过程的区别
当释放自定义类(带有析构函数)的对象时,它们的区别最为明显:
delete ptr;的执行过程:- 调用
ptr所指单个对象的析构函数。 - 调用
operator delete释放该对象所占用的内存。
- 调用
delete[] ptr;的执行过程:- 获取数组的长度(编译器通常会在分配数组内存时,在指针前面的隐藏区域存放一个记录数组大小的“Cookie”)。
- 按逆序对数组中的每一个对象调用析构函数。
- 调用
operator delete[]释放整个数组占用的内存块。
代码示例:
#include <iostream>
class MyClass {
public:
MyClass() { std::cout << "构造函数\n"; }
~MyClass() { std::cout << "析构函数\n"; }
};
int main() {
std::cout << "--- 测试 new 和 delete ---\n";
MyClass* p1 = new MyClass();
delete p1;
// 输出: 1次构造函数, 1次析构函数
std::cout << "\n--- 测试 new[] 和 delete[] ---\n";
MyClass* p2 = new MyClass[3];
delete[] p2;
// 输出: 3次构造函数, 3次析构函数
return 0;
}
3. 错误混用会引发什么后果?(极度危险)
这是 C++ 中最容易引发崩溃和内存泄漏的错误之一,属于 未定义行为 (Undefined Behavior, UB)。
错误情况 A:
new[]搭配deletecppMyClass* arr = new MyClass[10]; delete arr; // 错误!后果: 编译器只会调用
arr[0]的析构函数,剩下 9 个对象的析构函数不会被调用。如果这些对象内部动态分配了内存(比如包含std::string或指针),就会导致内存泄漏。此外,底层的内存释放函数可能会因为找不到正确的内存块元数据(Cookie)而导致程序直接崩溃。错误情况 B:
new搭配delete[]cppMyClass* obj = new MyClass(); delete[] obj; // 错误!后果: 编译器会错误地认为
obj指向的是一个数组,它会尝试去obj前面的内存地址读取“数组长度”,读出来的通常是垃圾数据(比如一个极大的数字)。然后它会尝试对这么多个不存在的对象调用析构函数,这会导致严重的内存越界访问,程序几乎必定崩溃。
4. 对于基本数据类型(如 int, char)有区别吗?
如果分配的是基本类型:
int* p = new int[10];
delete p; // 错误,但可能不会立刻崩溃
由于 int 没有析构函数,很多编译器在底层直接把整块内存释放掉了,程序可能“碰巧”正常运行。
但是: 这种写法在 C++ 标准中依然被明确规定为 未定义行为 (UB)。在不同的编译器、操作系统或内存分配器下,它仍然可能导致堆损坏或崩溃。因此,无论是什么数据类型,必须严格遵守 new/delete 和 new[]/delete[] 配对的原则。
5. 现代 C++ 的建议
在现代 C++(C++11 及以后)中,强烈建议不要直接使用 new 和 delete。你应该使用智能指针和标准库容器来自动管理内存:
- 代替
new / delete:使用std::unique_ptr或std::shared_ptr。 - 代替
new[] / delete[]:使用std::vector(首选)或者std::unique_ptr<T[]>。
// 现代 C++ 写法,不需要手动 delete
#include <memory>
#include <vector>
// 单个对象
std::unique_ptr<MyClass> p1 = std::make_unique<MyClass>();
// 动态数组(首选做法)
std::vector<MyClass> vec(10);
// 动态数组(智能指针做法)
std::unique_ptr<MyClass[]> p2 = std::make_unique<MyClass[]>(10);