malloc
和new
的区别
-
malloc
是按字节开辟空间的,new
开辟内存时需要指定类型(new int()
),malloc
开辟内存返回的都是void*
,而new
返回的是对应类型的指针 -
malloc
负责开辟空间,new
不仅有malloc
的功能,还可以进行数据初始化和构造对象,比如:new int(10)
。new
有开辟空间和构造的功能。 -
malloc
开辟内存失败返回nullptr
,而new
则会抛出bad_alloc
异常 - 我们调用
new
实际上是调用的operator new
,可以重载operator new
free
和delete
的区别
-
delete
先调用析构函数,再释放空间(即free
) - 我们调用
delete
实际上是调用的operator delete
,可以重载operator delete
我们先重载一下new、delete,添加测试类
存在自定义构造析构函数,new[]
可以看到,我们要分配5个Test对象的空间,这5个对象的空间为20字节,而size却是24,还多出了4字节空间。是的,malloc就是需要多分配4字节空间用于存储对象的个数,以便delete[]
执行指定次数析构函数
delete正确执行析构函数了,还要释放空间,即free,那free怎么知道要释放多少空间?
malloc会多分配4字节空间用于存放5个Test对象的个数,然后返回开辟空间的地址,在这个地址之前还有8字节,叫做块头,存放了真正给用户动态开辟的空间大小,也就是24
delete[]在释放空间的时候,会在用户传入地址往前查看4字节,执行指定次数析构函数后再执行free,free会在这24字节空间再往前偏移8字节,查看需要释放的内存大小(24),连同块头的8字节一起释放
当前场景下是内存这样,而为了防止病毒任意修改内存信息,某些平台可能会做一定的优化,比如在块头和分配的内存之间存在的填充
无自定义析构函数,new[]
测试类如下:
测试代码如下:
此时传入new[]的size变成了20,少了我们之前用于存储对象个数的4字节空间
对于内置的数据类型和没有自定义析构函数的类类型,new和new[]分配空间的时候,不会额外分配4字节存储对象的个数,依然会存在8字节的块头。只要是不额外分配4字节存储对象的个数,new和new[]、delete和delete[]混用不会出错
开辟方式 | 释放方式 | 结果 |
new | delete | 成功 |
new[] | delete | 内嵌类型和不提供自定义析构函数成功;提供自定义析构函数失败 |
new | delete[] | 内嵌类型和不提供自定义析构函数成功;提供自定义析构函数失败 |
new[] | delete[] | 成功 |
对于提供自定义析构函数的类类型,用new[]开辟空间,用delete释放空间出错。new[]会开辟4字节存储对象的个数,执行delete时,直接往前偏移8字节获取开辟的内存大小,由于存在4字节内存存储对象的个数,实际需要偏移12字节才能获取块头信息进行空间正确释放。此外,只执行可一个对象的析构函数,而new[]构造了一个对象数组,这也不正确。
同理,对于提供自定义析构函数的类类型,用new开辟空间,用delete[]释放空间也出错。因为new没有开辟4字节存储对象个数,而delete以为存在这4字节,执行析构函数的次数就从块头获取了,这不正确。想要访问块头,执行delete[]时会偏移12字节,越过了块头,这也会出问题。
参考:为什么new/delete和new[]/delete[]必须配对使用?