动态内存管理
C++中 malloc不调用构造函数,free 不调用析构函数。因此对象的资源依旧存在,只是对内存的空间进行申请,释放的。所以C++有自己的内存管理——new,delete。从而申请释放空间。
申请的地址空间(new,malloc申请那样)就在堆那里。
局部变量就在栈那里。
局部变量的值在代码段。
例子:char a[]="asdf"; char a[]:在栈;"asdf":在代码段,因为它是字符常量。
栈又叫堆栈,非静态局部变量/函数参数/返回值等等,栈是向下增长的。
堆用于程序运行时动态内存分配,堆是可以上增长的。
数据段--存储全局数据和静态数据。
代码段--可执行的代码/只读常量。
C语言中动态内存管理方式:
空间申请:
void malloc(size_t num);
void calloc(size_t num,size_t size); num是元素个数;size是单个元素大小
void* realloc(void* p,size_t size); p:地址;size是字节数
空间释放:
free(void* p) p:释放空间首地址
比较:
用的时候一定要free!!
C++语言中动态内存管理方式:
malloc/free:可以继续使用,但是一般不使用,因为只负责空间申请以及释放,不负责构造和销毁。
new/delete:申请和释放单个对象
new[ ] /delete[ ]:申请和释放一段连续的空间
注意:一定要匹配使用,否则就会资源泄漏!!!
new:(是关键字)
int* p1 = new int; //单个int类型的空间 //不用强制转换 int* p2 = new int(10); //可以初始化 //初始化10 int array[10]; //问:数组类型——int[10] //名字拿掉剩下的 //问元素类型——int(整型) int* p3 = new int[10]; int* p4 = new int[10]{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; //初始化
这也看出了new 和 malloc 的区别。不判空,不传字节数,不强转,可以初始化,调用构造/析构函数。
malloc 只是申请与对象大小一样的空间,不进行构造空间;delete是对完整对象进行销毁,释放对象。
delete:(是关键字)
int* p1 = new int; //单个int类型的空间 //不用强制转换 int* p2 = new int(10); //可以初始化 //初始化10 int array[10]; //问:数组类型——int[10] //名字拿掉剩下的 //问元素类型——int(整型) int* p3 = new int[10]; int* p4 = new int[10]{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; //初始化 delete p1; delete p2; delete[] p3; delete[] p4;
注:new 和 delete 一定要匹配使用。
类中的使用:
Date* p5=new Date (2019, 5, 16); //调用了构造函数 delete p5; Date* p6 = new Date[10]; //所指空间 10个Date对象的空间 delete[] p6;
new所做的事情:
- 申请空间
- 调用构造函数构造成完整的对象
delete做的事情:
- 调用析构函数清理对象资源
- 释放对象的内存空间
new T[N]:就是重复N次new操作
delete[ ]:就是重复deleteN次操作
operator new与operator delete函数:
new 在底层实现就是调用operator new函数:
new(字节数)——>循环调用 malloc函数
malloc 成功:返回空间首地址;malloc 失败(内存空间不足):执行用户定义的措施,没有措施就抛出异常。它是不会返回NULL。
delete 在底层实现就是调用operator delete函数:
通过 free函数 来释放空间的。
内存池:
内存的申请很慢,容量也不够,内存池非常方便,申请效率快,没有额外空间的浪费,也就是提前申请一块内存空间,需要只用割下来一部分,就用;不够,继续给就好了。类似银行卡,需要就刷卡,没了打钱就好了。
函数:
头文件:
#include<memory>
allocator<对象>().allocate(1); 1:表示对象的个数
void* operator new(size_t n) { //将new 重载成创建内存池 void* p = nullptr; p = allocator<ListNode>().allocate(1); cout << "memory pool allocate" << endl; return p; }
allocator<ListNode>().deallocate((ListNode*)p, 1); 内存池还回来。
定位new表达式:
无意中写成malloc函数,而不是new,这时候可以在malloc创建的空间上执行构造函数,也就可以实现对象的new。
//pt现在指向的只不过是与Test对象相同大小的一段空间,还不能算是一个对象,因为构造函数没有执行 Test* pt = (Test*)malloc(sizeof(Test)); new(pt) Test; // 注意:如果Test类的构造函数有参数时,此处需要传参
释放空间就delete 就好了。