好的,这个问题是 C 和 C++ 内存管理对比 的核心问题之一,我帮你系统梳理一下 new / delete 与 malloc / calloc / realloc / free 的区别与联系。

本人注解:首先需明确,这都是在堆上分配和释放内存的关键字或函数(严格来讲都是函数)

从这几个函数也可以看出C也好或C++也好都没有管理内存自动申请和释放的机制,这一点和java、python还是很有区别的


1. 归属与定位

特性 C 语言 C++
分配 / 释放方式 函数调用 运算符(关键字)
头文件 <stdlib.h> <new>delete 不需要头文件)
适用场景 C 和 C++ 都可用 仅 C++ 可用

有一点需要明确,c++中也是可以使用 malloc / calloc / realloc / free这些函数的,而c中则是不能使用new和delete的


2. 功能对应关系

C 语言 C++ 等价 说明
malloc(size) new 分配内存
calloc(num, size) new + 初始化(或 std::vector 分配并初始化为 0
realloc(ptr, size) 无直接等价,需手动拷贝 重新分配大小
free(ptr) delete 释放内存
malloc(n*size) + memset(0) new T[n](C++11 后可值初始化) 数组分配并清零

3. 核心区别

以下从返回指针类型的处理,以及对C++特有的构造析构函数的调用,失败处理的方式和内存管理方面来详细解释不同之处,使用时也需非常注意

(1) 类型安全

  • malloc / calloc / realloc
    • 返回 void*,需要强制类型转换
    • 不检查类型大小是否正确(完全依赖程序员)

    c运行

    int *p = (int*)malloc(sizeof(int));
    
  • new
    • 返回具体类型的指针,无需强制转换(这一点需要关注和知道)
    • 编译器会自动计算所需内存大小

    cpp运行

    int *p = new int;
    

(2) 构造函数 / 析构函数调用

  • malloc / free
    • 只分配 / 释放原始内存,不会调用对象的构造函数或析构函数

    c运行

    struct Test { Test() { printf("Construct\n"); } ~Test() { printf("Destruct\n"); } };
    Test *t = (Test*)malloc(sizeof(Test)); // 不会打印 "Construct"
    free(t); // 不会打印 "Destruct"
    
  • new / delete
    • new 会调用对象的构造函数
    • delete 会调用对象的析构函数

    本人注:关于对构造函数和析构函数的区别,其实也非常好理解,构造函数和析构函数本身就是C++中独有的概念

    cpp运行

    Test *t = new Test; // 打印 "Construct"
    delete t; // 打印 "Destruct"
    

(3) 数组内存管理

  • C 语言
    • malloc(n * sizeof(T)) 分配数组,不会调用构造 / 析构
    • 释放用 free

    c运行

    int *arr = (int*)malloc(10 * sizeof(int));
    free(arr);
    
  • C++
    • new T[n] 分配数组,会调用每个元素的构造函数
    • delete[] 释放数组,会调用每个元素的析构函数

    cpp运行

    Test *arr = new Test[3]; // 3次构造
    delete[] arr; // 3次析构
    

    ⚠ 必须配对使用 new[] / delete[],否则行为未定义


(4) 失败处理

  • malloc / calloc / realloc
    • 失败时返回 NULL
    • 需要手动检查返回值

    c

    运行

    int *p = (int*)malloc(sizeof(int));
    if (p == NULL) { /* 处理错误 */ }
    
  • new
    • 失败时抛出 std::bad_alloc 异常
    • 可以用 nothrow 版本返回 NULL

    cpp

    运行

    int *p = new(std::nothrow) int;
    if (p == nullptr) { /* 处理错误 */ }
    

(5) 自定义内存管理

  • C++ 可以重载 operator new / operator delete 控制内存分配方式
  • C 没有直接的重载机制,只能自己写分配 / 释放函数

4. 联系

  • 底层关系在大多数 C++ 实现中,new 内部会调用 malloc 分配内存,delete 内部会调用 free 释放内存
  • 混合使用(不推荐)
    • malloc 分配的内存不能用 delete 释放(会跳过析构函数,可能崩溃)
    • new 分配的内存不能用 free 释放(可能导致未定义行为)
    • 数组版本同样不能混用

5. 代码示例对比

单个对象

cpp

运行

// C
int *p1 = (int*)malloc(sizeof(int));
*p1 = 42;
free(p1);

// C++
int *p2 = new int(42); // 直接初始化
delete p2;

数组

cpp

运行

// C
int *arr1 = (int*)malloc(10 * sizeof(int));
free(arr1);

// C++
int *arr2 = new int[10](); // 值初始化,全部为0
delete[] arr2;

类对象

cpp

运行

struct Test {
    Test() { printf("Construct\n"); }
    ~Test() { printf("Destruct\n"); }
};

// C++
Test *t = new Test; // 构造
delete t; // 析构

// C(不会调用构造/析构)
Test *t2 = (Test*)malloc(sizeof(Test));
free(t2);

6. 总结对比表

特性 malloc / calloc / realloc / free new / delete
语言 C / C++ C++
分配 / 释放 函数调用 运算符
数组版本 无专用版本(手动计算大小) new[] / delete[]
返回类型 void*,需强转 返回具体类型指针
构造 / 析构 不调用 会调用
失败处理 返回 NULL 抛出异常(或 nothrow 返回 nullptr
重载能力 可重载 operator new/delete
底层关系 C++ 的 new 常调用 malloc 实现 内部可能调用 malloc / free

✅ 结论

  • C++ 中优先使用 new / delete(它们是类型安全的,并会调用构造 / 析构函数)
  • 与 C 库或底层 API 交互时,才使用 malloc / free
  • 绝对不要混用 malloc + delete 或 new + free
  • 对于动态数组,C++ 推荐使用 std::vector 而不是手动 new[]
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐