一、区别是什么?
申请的位置不同
- 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
{
//...
}
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提供的函数,它们的内部都是调用系统调用实现的