最近在复习C++ 的时候看到了这个问题,然后在网上查阅了一些资料,发现这个问题还是个十分易考的面试题,这里就给大家总结了一下,这两套东西到底是有什么区别。
首先要明白的是我们的new是运算符,他并不是一个函数,delete也是,而我们的malloc是库函数,他们都可以用来申请内存和释放内存,从表面看来既然都是一样的,那为啥C++里边要再弄一个new而不是直接用以前C中的malloc,是因为我们的C++中有了类,他就出现了很多的非内置类型的数据,是我们自定义的类型,这种类型的对象,在创建的时候就需要调用构造函数,在释放的时候也不只是简简单单的释放掉,是需要调用我们类中的析构函数,但是我们的malloc和free是我们的库函数,是不受编译器控制的,我们没办法对他进行修改。并且如果我们去看new实现的源码对比malloc
这是new的底层实现
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{ // 尝试申请内存空间
void *p; //这个指针用于指向获取到的空间,且返回该指针给调用方,且设置为void*是为了能够指向任意格式
while ((p = malloc(size)) == 0) //利用malloc函数调用来申请内存空间,得到一个闲置链表
if (_callnewh(size) == 0)
{ // 抛出没内存的信息
_THROW_NCEE(_XSTD bad_alloc, );
}
return (p);
}
发现new的本质就是调用了我们的malloc函数。
这是malloc函数的底层实现。
void *malloc(unsigned int size)
{
char *caddr; //虽然unsigned char* caddr是编译器认可的最小内存申明,但这里我们使用 char *
if (!malloc_ptr)
return NULL;
if ((malloc_ptr + size + sizeof(int)) > malloc_top) {
prom_printf("malloc failed\n");
return NULL;
}
*(int *)malloc_ptr = size;
caddr = malloc_ptr + sizeof(int);
malloc_ptr += size + sizeof(int);
last_alloc = caddr;
malloc_ptr = (char *)((((unsigned int)malloc_ptr) + 3) & (~3));
return caddr;
}
可以粗略的看出,malloc函数是不会去计算用户所需要的内存空间,需要用户自己去计算自己需要的空间大小,例如在数组中,malloc是需要用户自己给出计算后的大小,而new会额外储存数组大小,不需要用户再次进行计算。也就是说,new 基于 malloc,却又高于malloc,是它的一个提升版本。
在网上看到了关于new和malloc的几点不同:
这里用了其他人博客里边的一张图
第一点我并不是很懂,但是简单的来说就是malloc一定是在堆上开辟空间,但是我们的new在重载之后可能在堆也可能在静态区。
这里第二点的意思是说,我在malloc的时候返回的指针类型都是void*的所以每次malloc前我们都是需要进行强转的,但是new就不需要,我们new的是什么类型,返回的就是什么类型的指针。
第三点,我们在C语言里边开辟空间的时候经常会对返回的指针进行一个判断如果指针是空的话那么我开辟空间的过程就是失败的,但是new是不会的,他会直接抛出异常不会出现返回NULL的情况,第四点就是我们上边说的,假如我们现在开辟一个A的大小。
A * ptr = new A;
A * ptr = (A *)malloc(sizeof(A)); //需要显式指定所需内存大小sizeof(A);
这就是第四点的区别。
第五点对数组的处理中C++提供了new[]与delete[]来专门处理数组类型:new对数组的支持体现在它会分别调用构造函数函数初始化每一个数组元素,释放对象时为每个对象调用析构函数。注意delete[]要与new[]配套使用,不然会找出数组对象部分释放的现象,造成内存泄漏至于malloc,它并知道你在这块内存上要放的数组还是啥别的东西,反正它就给你一块原始的内存,在给你个内存的地址就完事。所以如果要动态分配一个数组的内存,还需要我们手动自定数组的大小。malloc就是给了你一片地,但是new不仅给你地还给你画好了区域这干什么那干什么。
第六点是对已经分配的内存的处理使用malloc分配的内存后,如果在使用过程中发现内存不足,可以使用realloc函数进行内存重新分配实现内存的扩充。realloc先判断当前的指针所指内存是否有足够的连续空间,如果有,原地扩大可分配的内存地址,并且返回原来的地址指针;如果空间不够,先按照新指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来的内存区域。这个功能new是实现不了的。
第七点的相互调用的意思我没理解错应该就是new去调用我们的malloc,malloc不能去调用我们的new。
第八点我理解的也不是很透彻,大致意思就是如果分配失败了,我们的malloc就没救了,停止了,但是new就不一样,虽然他会抛出异常但是当你分配失败了之后还是有挽救的机会的。
第九点函数重载,重载算是C++一个大的特性了,new自然也少不了,但是库里边提供的new重载函数就有八个之多,每个都有自己的用处。
第十点在我看来算是是为什么会有new的原因吧,就是非内部类型的构造和析构函数的调用,我们在开头就说过了。
对于new和malloc的不同就先介绍这么多,我认为已经很详细了,之前并不知道有这么多的区别,还是需要去理解,不能死记硬背这十个特点,明白两个东西的本质最重要。