基于本文回答

播面 播面

文图音视,全方位拆解八股文
0
评论

C++ delete 和 delete[] 有什么区别?

知识点图片

在 C++ 中,deletedelete[] 都是用来释放动态分配的内存的操作符,但它们的使用场景和底层行为有着严格的区别。

核心的区别可以用一句话概括:delete 用于释放单个对象的内存,而 delete[] 用于释放对象数组的内存。

下面是详细的区别和原理解析:

1. 匹配规则

  • 如果你用 new 分配内存,必须用 delete 释放。
  • 如果你用 new[] 分配内存,必须用 delete[] 释放。
cpp
// 1. 单个对象
int* p1 = new int(10);
delete p1;   // 正确

// 2. 数组对象
int* p2 = new int[10];
delete[] p2; // 正确

2. 底层执行过程的区别

当释放自定义类(带有析构函数)的对象时,它们的区别最为明显:

  • delete ptr; 的执行过程:

    1. 调用 ptr 所指单个对象的析构函数。
    2. 调用 operator delete 释放该对象所占用的内存。
  • delete[] ptr; 的执行过程:

    1. 获取数组的长度(编译器通常会在分配数组内存时,在指针前面的隐藏区域存放一个记录数组大小的“Cookie”)。
    2. 按逆序对数组中的每一个对象调用析构函数。
    3. 调用 operator delete[] 释放整个数组占用的内存块。

代码示例:

cpp
#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[] 搭配 delete

    cpp
    MyClass* arr = new MyClass[10];
    delete arr; // 错误!

    后果: 编译器只会调用 arr[0] 的析构函数,剩下 9 个对象的析构函数不会被调用。如果这些对象内部动态分配了内存(比如包含 std::string 或指针),就会导致内存泄漏。此外,底层的内存释放函数可能会因为找不到正确的内存块元数据(Cookie)而导致程序直接崩溃

  • 错误情况 B:new 搭配 delete[]

    cpp
    MyClass* obj = new MyClass();
    delete[] obj; // 错误!

    后果: 编译器会错误地认为 obj 指向的是一个数组,它会尝试去 obj 前面的内存地址读取“数组长度”,读出来的通常是垃圾数据(比如一个极大的数字)。然后它会尝试对这么多个不存在的对象调用析构函数,这会导致严重的内存越界访问,程序几乎必定崩溃

4. 对于基本数据类型(如 int, char)有区别吗?

如果分配的是基本类型:

cpp
int* p = new int[10];
delete p; // 错误,但可能不会立刻崩溃

由于 int 没有析构函数,很多编译器在底层直接把整块内存释放掉了,程序可能“碰巧”正常运行。
但是: 这种写法在 C++ 标准中依然被明确规定为 未定义行为 (UB)。在不同的编译器、操作系统或内存分配器下,它仍然可能导致堆损坏或崩溃。因此,无论是什么数据类型,必须严格遵守 new/deletenew[]/delete[] 配对的原则。

5. 现代 C++ 的建议

在现代 C++(C++11 及以后)中,强烈建议不要直接使用 newdelete。你应该使用智能指针和标准库容器来自动管理内存:

  • 代替 new / delete:使用 std::unique_ptrstd::shared_ptr
  • 代替 new[] / delete[]:使用 std::vector(首选)或者 std::unique_ptr<T[]>
cpp
// 现代 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);
00:00
00:00