面试题:C++ 中为什么 new[] 和 delete[] 一定要配对使用?

在 C++ 中,new[] 和 delete[] 必须配对使用,因为它们的行为与 new 和 delete 有本质区别。混用 new[] 和 delete 或 new 和 delete[] 会导致未定义行为(undefined behavior),可能引发程序崩溃或内存泄漏。


为什么 new[] 和 delete[] 必须配对使用?

1. 内存分配和释放的机制不同

  • new[]
    • 用于分配数组内存。
    • 除了分配内存外,还会调用每个数组元素的构造函数。
    • 在分配的内存块中可能会存储数组的大小(用于 delete[] 正确释放内存)。
  • delete[]
    • 用于释放数组内存。
    • 除了释放内存外,还会调用每个数组元素的析构函数。
    • 需要知道数组的大小,以便正确调用析构函数并释放内存。
  • new
    • 用于分配单个对象的内存。
    • 只调用单个对象的构造函数。
  • delete
    • 用于释放单个对象的内存。
    • 只调用单个对象的析构函数。

2. 内存布局可能不同

  • new[] 可能会在分配的内存块中存储数组的大小,而 new 不会。
  • 如果使用 delete 释放 new[] 分配的内存,可能会导致:
    • 只调用第一个元素的析构函数,而其他元素的析构函数未被调用。
    • 内存释放不完整,导致内存泄漏或程序崩溃。

3. 未定义行为

  • 混用 new[] 和 delete 或 new 和 delete[] 是未定义行为,具体表现取决于编译器和运行时环境,可能导致:
    • 程序崩溃。
    • 内存泄漏。
    • 数据损坏。

示例分析

1. 正确用法

class MyClass {
public:
    MyClass() { std::cout << "Constructed!" << std::endl; }
    ~MyClass() { std::cout << "Destroyed!" << std::endl; }
};

int main() {
    MyClass* arr = new MyClass[3]; // 调用 3 次构造函数
    delete[] arr; // 调用 3 次析构函数
    return 0;
}

输出:

Constructed!
Constructed!
Constructed!
Destroyed!
Destroyed!
Destroyed!

2. 错误用法(混用 new[] 和 delete

int main() {
    MyClass* arr = new MyClass[3]; // 调用 3 次构造函数
    delete arr; // 未定义行为:只调用第一个元素的析构函数
    return 0;
}

可能的输出:

Constructed!
Constructed!
Constructed!
Destroyed!
  • 只有第一个元素的析构函数被调用,其他元素的析构函数未被调用。
  • 内存释放不完整,可能导致内存泄漏或程序崩溃。

3. 错误用法(混用 new 和 delete[]

int main() {
    MyClass* obj = new MyClass; // 调用 1 次构造函数
    delete[] obj; // 未定义行为:尝试释放未分配的内存
    return 0;
}

可能的输出:

Constructed!
  • 程序可能崩溃或产生不可预测的行为。

总结

  • new[] 和 delete[] 必须配对使用,因为它们专门用于数组的内存管理。
  • new 和 delete 必须配对使用,因为它们专门用于单个对象的内存管理。
  • 混用会导致未定义行为,可能引发程序崩溃、内存泄漏或数据损坏。

这个问题考察的是对 C++ 内存管理机制的理解,尤其是 new[] 和 delete[] 的特殊行为。

THE END
点赞15 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容