C++ new和malloc的区别

前言

刚才在STL复习中,复习到SCI stl的两层空间配置器时,又说到SGI stl第一层使用malloc配置空间,我想为什么不用malloc呢,突然记起来一直堆new和malloc的区别都没太了解,正好现在先完成这部分。

note: 本博客参考自 https://www.cnblogs.com/ywliao/articles/8116622.html 感谢原作者

new和malloc的10点区别

1.申请内存的位置

new操作符是从自由存储区为对象动态分配内存空间,而malloc则是在堆上分配空间,注意此处的不同,new用于对象的内存分配,而malloc是内存分配,这在后面也有详细解释。

自由存储区是一个基于c++new操作符的一个抽象盖帘,凡是通过new操作符申请内存,该内存即是自由存储区。对应的堆是一个(操作系统的概念,相对操作系统来讲是一个实际的概念,但是相对于我们来说又是一个抽象的概念)。一般来讲,操作系统为每一个程序都维护了一段空间,用来保存各部分数据,包括代码段,数据段,静态数据段等,其中还有栈空间一般是保存的是一些临时变量,而堆空间申请的内存在整个程序的存活期内都是有效的。

通过上面的介绍,自由存储区是否可以是堆呢,这要取决于new的实现细节,自由存储区可以是堆,静态存储区等,这取决于new从那一部分区分配内存。

特别地,new可以不为对象分配内存,
new(place_adress) type
place_adress为一个指针,代表一块内存的地址,当使用此种方式仅以一个地址调用new操作符时,new

2.返回类型

对于new来说,申请内存成功后返回的是一个对象的指针或者一个基本类型的指针,无需进行类型转换,

int *a = new int;
*a=5;

反观malloc函数原型:

(void*) malloc(size_t);

在申请到空间后需要根据需要进行强制类型转换,当然也可以转换为基本类型或者一个对象指针。

3.内存分配失败的返回值

new分配内存失败时是抛出一个bad_alloc的异常,不会返回NULL。与之相比malloc在内存分配失败后会返回NULL,我们可以通过一个if语句来观察到是否分配成功。

int *b = (int *)malloc(sizeof(int));
if(b==NULL){...}

而对于new采用这种方法完全不可行。
对应的处理方式为

try
{
    int *a = new int();
}
catch (bad_alloc)
{
    ...
}

4.是否需要指定内存大小

使用new进行内存分配时不需要指定内存块的大小。编译器会自行根据类型信息判断。相比于malloc,则需要显示的指出当前需要分配的快内存大小。

5.是否调用构造/析构函数

如之前在STL源码剖析里面提到的,一个对象从生成到销毁经历了如下步骤:1.new分配内存空间 2.构造函数构造对象,并传入初值 3.析构函数销毁对象 4. 通过delete释放空间。

对比于malloc,就只是分配一块内存空间。不会自动调用对应的构造函数,因此分配的空间将没有初始值。这也就是为什么自定义对象最好不要使用malloc来进行内存分配的原因。

6.new和malloc是否可以相互调用

一般来讲,new和delete是可以通过调用malloc和free来进行内存分配的,这可以参考前面内存分配的位置。

7.是否可以重载

这个我们经常使用到的new可以重载[]运算符,delete也是如此,相反,malloc和free是不允许重载的。

8.是否能够重新分配内存

这一点对于new来讲,是不可以在第一次分配空间后,再次进行空间的增加的。反而对于malloc在空间不足时,可以通过realloc来增加连续的空间分配。如果原有空间后面有足够的连续空间,则原地扩大可分配空间,如果空间不足,则重新指定新的空间进行分配,并且将原来数据拷贝到新的空间,释放原来空间。(我猜想这一步也就是为什么vector或者说STL底层的空间配置使用malloc的原因,可以自由增加空间)

9.对数组的处理

对于new和delete 重载了new [] 和 delete[]来专门处理数组。但是需要注意的是两者必须配合使用,否则会导致内存泄漏。

而对于malloc和free,分配时并不知道这块内存要放什么东西。只是单纯给出了一块内存。如果要分配一块数组的空间,没有重载相应的类型,需要指定连续空间的大小。

总结

对以上new和malloc的总结如下:

特征 new/delete malloc/free
内存分配位置 自由存储区 堆空间
内存分配失败返回值 bad_alloc NULL
我分配内存大小 由编译器自行计算得出 需要使用sizeof计算块大小
数组处理 重载了new[] 需要计算数组大小后进行分配
是否进行二次分配 无法堆已经分配的空间扩充 可以使用realloc堆空间扩充
是否相互调用 new/delete可以调用malloc和free 不可以调用
是否调用构造/析构函数 调用 不调用