辨析new/delete、malloc/free、operator new

从c到c++:辨析new/delete、malloc/free、operator new

一、区别

从定义讲

  • malloc/free 是操作符
  • new/delete是函数
  • 因此,前者的使用必须引用头文件

从流程讲

  • malloc 申请了若干长度的内存,返回内存地址,仅此而已
  • new 首先申请若干内存,继而调用构造函数,返回值带有类型不需要指定,此过程中出现问题会自动抛出异常

综上,new不仅更高效,也更安全。
附实例

ListNode* pList = (ListNode*)malloc(sizeof(ListNode));

对比

ListNode* pList = new ListNode;

当然,delete对应new主要比free多了析构函数,否则内存泄漏。

再往深处说,c++还有operator new ,实际上通常new的执行过程中的分配内存由operator new
完成,再结合异常检查,以及构造函数就构成了new。

对于operator new还有更多细节,随后补充,Clion下不方便看库。

二、new/delete、new[]/delete[]

仍以new为例,new我们经常

ListNode* pList = new ListNode;

但有时我们还会

int *p = new int[10]

我们可以申请一组空间给p,如果你忘了delete[] 而是delete,则程序会崩溃。
原因显而易见:程序对于一个“数组”,并不知道需要析构多少次。
那么就有一个有趣的问题,delete[] 又怎么知道需要析构多少次?

vs下调试步入源码可以看到,对delete与delete[]申请的空间的结构是不一样的
-w500

如上图,new[]会多申请一个整型空间于整片内存的最前面,用以存储“数组元素长度”

同时,delete[]不同于delete,其会读取实际数据所在空间前的空间,以判断需要执行多少次析构。

三、operator new 简述

operator new有三种形式:

throwing (1)    
void* operator new (std::size_t size) throw (std::bad_alloc);
nothrow (2) 
void* operator new (std::size_t size, const std::nothrow_t& nothrow_value) >throw();
placement (3)   
void* operator new (std::size_t size, void* ptr) throw();

(1)(2)的区别仅是是否抛出异常,当分配失败时,前者会抛出bad_alloc异常,后者返回null,不会抛出异常。它们都分配一个固定大小的连续内存。
(3)是placement new,它也是对operator new的一个重载,定义于#include 中,它多接收一个ptr参数,但它只是简单地返回ptr。其在new.h下的源代码如下:


#ifndef __PLACEMENT_NEW_INLINE


#define __PLACEMENT_NEW_INLINE

inline void *__cdecl operator new(size_t, void *_P)
       {return (_P); }

#if     _MSC_VER >= 1200

inline void __cdecl operator delete(void *, void *)
   {return; }

#endif


#endif

那么它究竟有什么用呢?事实上,它可以实现在ptr所指地址上构建一个对象(通过调用其构造函数),这在内存池技术上有广泛应用。
它的调用形式为:

new(p) A(); //也可用A(5)等有参构造函数

引用自 http://blog.csdn.net/wudaijun/article/details/9273339

使用宏模拟new[] 以回顾上述问题以及简单探究operator new

#define NEW_ARRAY(PTR,TYPE,N)               \
do{                                         \   //定义do-while以避免宏出现优先级问题
PTR = (TYPR*)operator new(sizeof(TYPE)*N + 4); \    //申请若干空间并返回对应类型指针
(*(int*)PTR) = N;                          \    //存储对象个数,以方便随后析构
PTR = (TYPE*)((char*(PTR)+4));             \    //将指针向后移动,指向数据的开始
for (size_t i = 0; i < N; i++)                 \    
new(PTR + i)TYPE;                          \    //对应operator new第三种形式,手动构造
} while (false);

使用宏模拟delete[] ,对应new[]代码

#define DELETE_ARRAY(PTR,TYPE)     \
do{                                \
size_t N = *((int*)PTR - 1);       \
for (size_t i = 0; i < N; i++)     \
PTR[i].~TYPE();                \
PTR = (TYPE*)((char*)PTR - 4); \
operator delete(PTR);          \
} while (false);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值