一文说清new与malloc、delete与free的区别

一文说清new与malloc、delete与free的区别

编码文章call10242025-03-24 13:55:1715A+A-

C++ 提供了两套主要的内存分配与释放机制:

  • newdelete 操作符(C++ 风格)
  • mallocfree 函数(C 风格)

下面我们详细对比这两种机制的关键区别:


1. 类型安全与构造/析构调用

  • newdelete
    • 类型安全new 在分配内存的同时,会根据给定的类型自动返回对应类型的指针,不需要进行强制类型转换。例如:
 int* p = new int;        // 分配单个整数的内存
 int* arr = new int[10];    // 分配一个包含 10 个整数的数组内存
  • 对象构造:当使用 new 创建对象时,它不仅分配内存,还会调用对象的构造函数,从而完成初始化。
  • 析构调用:对应的 delete 操作符会调用对象的析构函数后,再释放内存:
 MyClass* obj = new MyClass();  
 // 使用完毕
 delete obj;              // 自动调用析构函数,然后释放内存
  • mallocfree
    • 无类型安全malloc 仅接收一个字节数,返回的是 void* 指针,需要手动进行类型转换:
     int* p = (int*)malloc(sizeof(int));
     int* arr = (int*)malloc(10 * sizeof(int));
  • 内存初始化问题malloc 分配的内存不会自动初始化(内存中的值不确定),即使对基本类型,也经常需要手动初始化。
  • 无构造/析构机制:对于对象来说,malloc 不会调用构造函数,free 也不会调用析构函数,这意味着使用 mallocfree 分配 C++ 对象会绕过对象的生命周期管理,从而容易引入错误。

2. 错误处理机制

  • new 操作符: 默认情况下,当内存分配失败时,new 会抛出 std::bad_alloc 异常。这使得错误处理更加面向对象,可以利用 try-catch 块来捕捉和处理异常:
   try {
       int* p = new int[1000000000];
   } catch (std::bad_alloc& ex) {
       std::cerr << "内存分配失败:" << ex.what() << std::endl;
   }
  • malloc 函数: 当内存分配失败时,malloc 会返回 NULL(或 nullptr,取决于 C 环境),需要显式地检查返回值:
   int* p = (int*)malloc(sizeof(int));
   if (p == NULL) {
       // 处理内存分配失败的情况
   }

3. 灵活性与扩展性

  • 操作符重载: C++ 允许对 newdelete 操作符进行重载,这为某些类提供了定制化的内存分配方式。这在需要高性能或特殊内存管理(如对象池)的时候非常有用:
   class MyClass {
   public:
       void* operator new(size_t size) {
           std::cout << "使用自定义 new 分配内存" << std::endl;
           return ::operator new(size);
       }
       void operator delete(void* ptr) {
           std::cout << "使用自定义 delete 释放内存" << std::endl;
           ::operator delete(ptr);
       }
   };
  • 兼容性与历史原因mallocfree 来自 C 语言,设计上更加底层、通用。而 newdelete 则是为了解决 C++ 对象生命周期管理以及类型安全等更高级的问题而设计的。

4. 内存分配细节及性能

  • 内存开销: 在大多数情况下,newmalloc 内部可能都调用底层操作系统的内存分配函数。
    • new 在调用对象构造函数之前,通常会有额外的操作,例如类型信息管理和对齐操作,这在某些情境下可能引入少量额外开销。
    • malloc 仅仅负责分配一块连续的内存,不涉及构造调用,相对更轻量,但也因此无法满足复杂对象的需求。
  • 数组分配
    • 对于数组,new[]delete[]malloc 分配的数组有本质上的区别。使用 new[] 分配的数组,在释放时需要使用 delete[] 才能正确地调用每个元素的析构函数。

5. 使用建议

  • 对于 C++ 对象: 尽量使用 newdelete 来管理内存,确保构造与析构能够被正确调用,同时利用类型安全特性。如果使用 STL(例如 std::vectorstd::unique_ptr),可以进一步消除手动内存管理的风险。
  • 对于简单的、与 C 语言兼容的数据结构: 如果只是分配一块内存存储数据,并且你不需要调用构造与析构函数,则可以使用 mallocfree。不过需要仔细管理指针转换和初始化工作。

ASCII 图示:内存分配过程对比

                +-------------------+
                |   使用 new 分配内存  |
                +-------------------+
                           |
                           V
            +-----------------------------+
            | 分配内存 + 调用构造函数       |
            +-----------------------------+
                           |
                           V
              +---------------------+
              |  对象使用成型       |
              +---------------------+
                           |
                           V
            +-----------------------------+
            | delete 释放内存 + 调用析构函数 |
            +-----------------------------+
 
                +---------------------+
                | 使用 malloc 分配内存 |
                +---------------------+
                           |
                           V
            +-----------------------------+
            | 仅分配内存,不调用构造函数   |
            +-----------------------------+
                           |
                           V
              +---------------------+
              | 数据存储,未初始化   |
              +---------------------+
                           |
                           V
              +---------------------+
              | free 释放内存       |
              +---------------------+

总结

  • 构造与析构new 自动调用构造函数,delete 自动调用析构函数,而 mallocfree 则不做这部分工作。
  • 类型安全new 返回合适的类型指针,无需强制转换;malloc 返回 void 指针,需要手动转换。
  • 错误处理new 分配失败会抛出异常,malloc 则返回 NULL
  • 适用场景:如果需要对象生命周期管理、类型安全以及更好的错误捕获,使用 new/delete。如果需要与 C 代码兼容或实现某些底层操作,可能会选择 malloc/free

总体而言,在 C++ 中推荐尽量使用 newdelete,或者更优选项是使用智能指针(如 std::unique_ptrstd::shared_ptr) 和标准容器来管理内存,从而实现 RAII(资源获取即初始化)的编程范式,确保内存管理既高效又安全。


此外,如果你对 C++ 内存管理细节、异常安全、以及智能指针的使用有更多兴趣,我可以介绍智能指针及 RAII 的更详细应用,帮助你更好地掌握 C++ 的现代内存管理理念。

点击这里复制本文地址 以上内容由文彬编程网整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

文彬编程网 © All Rights Reserved.  蜀ICP备2024111239号-4