基于本文回答
0
评论

new/delete 和 malloc/free 的本质区别是什么?

知识点图片

new/deletemalloc/free 都是在 C/C++ 中用于动态内存管理的工具,但它们的本质区别在于:new/delete 是面向对象的,而 malloc/free 是面向内存的。

换句话说,malloc/free 只负责分配和释放生肉(纯粹的字节),而 new/delete 不仅分配内存,还会把生肉做成熟菜(调用构造函数初始化对象,调用析构函数清理对象)

以下是它们的核心区别对比:

1. 本质与身份

  • new/delete:是 C++ 的内置运算符(Operator),受编译器控制,就像 +- 一样。
  • malloc/free:是 C/C++ 标准库中的函数(Function),包含在 <cstdlib> 库中。

2. 构造函数与析构函数(最核心的区别)

  • new:分为两步。第一步分配足够的内存,第二步自动调用该类型的构造函数来初始化对象。
  • delete:分为两步。第一步自动调用该对象的析构函数清理资源,第二步释放内存。
  • malloc/free:仅仅分配或释放指定字节数的内存,完全不知道“对象”的存在,绝不会调用构造和析构函数。
    (如果用 malloc 分配带有虚函数或含有 std::string 等复杂成员的 C++ 类,会导致灾难性错误,因为对象没有被正确初始化。)

3. 类型安全与返回类型

  • new:是类型安全的。你告诉它要什么类型,它就返回什么类型的指针(例如 new int 返回 int*),不需要强制类型转换
  • malloc:返回的是 void*(无类型指针)。在 C++ 中,必须手动进行强制类型转换才能赋值给特定类型的指针(例如 (int*)malloc(sizeof(int)))。

4. 内存大小的计算

  • new:编译器会自动计算需要的内存大小,你只需要提供类型(例如 new MyClass)。
  • malloc:需要你手动计算并传入需要分配的总字节数(例如 malloc(sizeof(MyClass)))。

5. 分配失败时的处理

  • new:如果内存分配失败,默认会抛出 std::bad_alloc 异常。程序需要用 try-catch 来捕获。(也可以使用 new (std::nothrow) 让它返回 NULL)。
  • malloc:如果内存分配失败,会返回 NULL 指针。程序员必须在每次调用后手动检查是否为 NULL。

6. 重载与自定义

  • new/delete:允许被重载(Overload)。你可以为特定的类重载 operator new,实现自定义的内存池管理。还支持 定位 new (Placement new),允许在已经分配好的内存上构建对象。
  • malloc/free:是标准库函数,不允许重载。

7. 内存区域

  • new/delete:从概念上讲,它们在 自由存储区(Free Store) 上分配内存。
  • malloc/free:在 堆(Heap) 上分配内存。
    (注:在绝大多数现代编译器的实现中,自由存储区底层就是用堆来实现的,new 的底层通常也会调用 malloc,但 C++ 标准在概念上将它们区分开来。)

8. 数组的处理

  • new/delete:有专门为数组设计的版本 new[]delete[]new[] 会记录数组的长度,并为每个元素调用构造函数;delete[] 会为每个元素调用析构函数。
  • malloc/free:只是分配一大块连续的字节,没有数组的概念。

总结图表

特性 new / delete malloc / free
属性 C++ 运算符 (Operator) 库函数 (Function)
对象生命周期 调用构造/析构函数 不调用,只管内存
返回类型 具体类型的指针 (类型安全) void* (需要强转)
参数 指定数据类型 指定字节数 (sizeof)
分配失败行为 抛出 bad_alloc 异常 返回 NULL
是否可重载 可以重载 不可重载
配套数组操作 new[] / delete[] 手动算总大小,直接 free

最佳实践与警告

  1. 在 C++ 中,永远优先使用 new/delete(或者更好的选择:智能指针 std::unique_ptr / std::make_shared),尽量不要在 C++ 代码中出现 malloc/free
  2. 绝对不能混用!
    • new 分配的内存,必须用 delete 释放。
    • malloc 分配的内存,必须用 free 释放。
    • new[] 分配的数组,必须用 delete[] 释放。
    • 如果混用(例如 new 出来用 free 释放),对于包含析构函数的类,会导致内存泄漏或未定义行为(程序崩溃)。
右滑查看面试常问