C++动态内存管理

本节重点:
1:总结并剖析malloc/free和new/delete之间关系和差异。
2:剖析new/delete、new[]/delete[]到底做了些什么事情。
3:实现NEW_ARRAY/DELETE_ARRAY宏,模拟new[]/delete[]申请和释放数组。
差异:
>>malloc是一个函数,而new是C++封装出来的一个操作符。
>>new delete 会调用构造和析构函数,(深拷贝,开辟空间并且进行初始化)而malloc直接开辟空间。(浅拷贝,只开辟空间并不会初始化)
关于调用构造函数和析构函数:
定位new:在指定的位置调用构造函数,而不进行开辟空间操作;
格式: Type * p= new (ptr) type;
普通new:开辟地址并初始化;
operate new:相当于C语言中的malloc,只负责申请内存;
格式: void* p= operator new(sizeof(string));

delete operate:普通的delete. 调用析构并且释放空间。
operate delete(PTR):释放指定位置的空间,相当于C语言中的free;
>> new能够自动计算需要分配的内存空间,而malloc需要手工计算字节数。
>> malloc/free需要库文件stdlib.h支持,new/delete则不需要库文件支持。
>> void *malloc(long NumBytes): malloc分配指定字节数,返回指向所开辟空间的指针(void 类型指针),开辟失败返回NULL;
   void free(void *FirstByte): free 是释放malloc所开辟的空间,返还给操作系统。传所开辟空间的起始地址。
>> new是类型安全的,而malloc不是,它必须自己强转类型麻烦易错。
例如,int* p=new float[2],编译时就会报错;而int* p=malloc(2*sizeof(float)),编译时编译器就无法指出错误来。
>> new一般由两步构成,分别是new操作和构造。new操作对应于malloc, 但new操作可以重载,可以自定义内存分配策略,不做内存分配,甚至分配到费内存设备上,而malloc不可以。
>>new开辟空间失败抛异常,malloc开辟失败返回NULL;


eg:int* p1 = (int*) malloc(sizeof (int));  //malloc函数的返回值
int* p2= new int;
注意malloc/free、new/delete、new[]/delete[]
一定匹配使用,一定匹配使用,一定匹配使用!!!重要的事说三遍!否则可能出现内存泄露甚至崩溃的问题.
如下代码不匹配使用会出现什么问题?为什么?
void Test ()
{
// 以下代码没有匹配使用,会发生什么?有内存泄露吗?会崩溃吗?
int* p4 = new int;  //开辟一个int
int* p5 = new int(3);  //开辟一个int,并且初始化为3
int* p6 = new int[3]; 
//开辟三个int,(事实上开辟了四个int的空间,第一个int空间存放一个开辟多少个的个数)
//然后指针向后移动四个字节,所以p6指向开辟数组的的第一个元素的起始位置。
int* p7 = (int*) malloc(sizeof (int));  //开辟一个int。
delete[] p4 ;//崩溃,多向前走了四个字节。
delete p5 ;//匹配使用,没问题。
free(p5 );//不会调用析构函数。
delete p6 ;//崩溃。应该向前移动四个字节
delete p7 ;//多调用一次析构函数。并无大碍。
剖析:
(1)new/delete
new做了两件事:1)调用operator new 分配空间;2)调用构造函数初始化对象.

delete做了两件事:1)调用析构函数清理对象;2)调用operator delete 释放空间.

(2)new[ ]/delete[ ]
new[ ]做了两件事:
1)调用operator new分配空间;开辟N*sizeof(类型)+4个空间,前四个字节存N(开辟的个数)。
2)调用N次构造函数分别对每个对象进行初始化.
delete[ ]做了两件事:
1)调用N次析构函数分别对每个对象进行清理;
2)调用operator delete 释放空间.
实现NEW_ARRAY/DELETE_ARRAY宏,模拟new[]/delete[]申请和释放数组。
#include<iostream>
using namespace std;
// new[ ]
#define _ARRAR_NEW_ARRAY(PTR,TYPE,N) \
do{
\
/*调用operate new 开辟空间;*/ \
PTR = (TYPE*)operate 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;/*定位new*/ \
} while (false)
//  delete[ ]
#define _ARRAR_DELETE_ARRAY(PTR,TYPE) \
do{ \
/*将指针向前移动四个字节,拿出N*/ \
size_t N = *(int*)((char*)PTR - 4); \
/*循环调用析构函数进行清理;*/ \
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、付费专栏及课程。

余额充值