C/C++面试:40---new/delete与malloc/free的区别是什么?底层是如何实现的呢?

一、区别是什么?

申请的位置不同

  • new操作符从自由存储区(free store)上为对象动态分配内存空间,而malloc函数从堆上动态分配内存
  • 自由存储区是C++基于new操作符的一个抽象概念,凡是通过new操作符进行内存申请,该内存即为自由存储区
  • 堆是操作系统中的术语,是操作系统所维护的一块特殊内存,用于程序的内存动态分配,C语言使用malloc从堆上分配内存,使用free释放已分配的对应内存

类型不同

  • new/delete是C++的一种运算符,malloc/free是C提供的函数
  • 对于内置类型而言,C语言提供的malloc可以使用
  • 但是C++提供了构造函数、析构函数与非内置类型(类类型)的概念,因此malloc函数就不能满足需求了(见下)

构造函数、析构函数

  • 在C语言中,没有构造函数和析构函数的概念,因此使用malloc来创建对象没有问题
  • 但是C++提供了构造函数、析构函数、类类型等概念,因此:
    • 在创建对象的时候需要调用构造函数
    • 在销毁对象的时候需要调用析构函数
  • C++的new和delete就具有这些特性
  • 当调用new创建对象时,其内部实际上:
    • 先在内部调用malloc分配一块内存
    • 然后基于这个内存调用构造函数来构造对象
    • 构造完成之后,返回指向对象的指针
  • 当调用new创建对象时,其内部实际上:
    • 先调用对象的析构函数
    • 之后再内部调用free()释放内存

类型检查

  • malloc函数不关心你创建对象的类型,因此其只是创建指定大小的内存,然后将内存起始地址返回给调用者,因此调用者需要自己进行强制类型的转换
  • new运算符在创建对象时需要指定对象的类型。因此,new是符合类型安全性的操作符
  • 例如:
int* p = new float[2];            // 编译时指出错误

int* p = malloc(2*sizeof(float)); // 编译时无法指出错误

内存分配失败时的处理

  • new内存分配失败时,会抛出bac_alloc异常,它不会返回NULL
  • malloc分配内存失败时返回NULL
  • 因此,当调用malloc失败时的处理如下所示:
int *p = (int*)malloc(int);
if(p == NULL)
{
    //...
}
else
{
    //...
}
  • 当调用new失败时的处理如下所示:
try
{
    int *p = new int(1);
}
catch(bad_alloc)
{
    //...
}

是否需要指定内存大小

  • 使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算
  • malloc则需要显式地指出所需内存的尺寸
  • 例如:
class A{...}
A * ptr = new A;
A * ptr = (A *)malloc(sizeof(A)); //需要显式指定所需内存大小sizeof(A);

能否重载

  • malloc和free不可以重载
  • 但是new和delete可以重载

二、它们的底层是如何实现的?

new和delete

  • new的内部是调用malloc()函数和构造函数实现的
  • delete的内部实际上是调用free()函数和析构函数来释放内存的
  • 当调用new创建对象时,其内部实际上:
    • 先在内部调用malloc分配一块内存
    • 然后基于这个内存调用构造函数来构造对象
    • 构造完成之后,返回指向对象的指针
  • 当调用new创建对象时,其内部实际上:
    • 先调用对象的析构函数
    • 之后再内部调用free()释放内存

malloc()和free()

  • malloc()和free()是glibc提供的函数,它们的内部都是调用系统调用实现的

猜你喜欢

转载自blog.csdn.net/qq_41453285/article/details/107764836