目录
四.operator new和operator delete函数
一.C/C++内存分布
补充说明:
- 栈又叫堆栈,主要保存非静态局部变量/函数参数/返回值/返回地址等等,栈是向下增长的。
- 内存映射区,时高效I/O映射方式,用于装载一个共享的动态内存库。用户可以使用系统接口创建共享内存,做进程间的通信。
- 堆,用于程序运行时动态内存的分配,堆是向上增长的。
- 数据段,存储全局数据和静态数据
- 代码段,用于存储可执行代码和只读常量。
参考:C/C++内存分配
二.C语言中动态内存管理方式
可见博客:C语言动态内存管理
这里回顾一下。
C语言用过malloc/calloc/realloc来在堆上动态申请空间,通过free来释放空间。
malloc/calloc/realloc三者区别:
malloc:只是在堆上动态申请多少字节的空间。一般用法:(类型 *)malloc(sizeof(类型)),返回值为void *所以需要强转。
calloc:不仅有malloc的功能,还具有将空间值初始化为0的功能。一般用法:(类型 *)calloc(x,sizeof(类型)),申请x*sizeof(类型)字节的空间。
realloc:是对在堆上申请的空间不够时,进行扩容。返回地址如果原有地址后面扩容空间够,返回原来地址,不够重新在另外一处开辟空间,返回新地址。(void *)realloc(需要扩容空间地址,空间大小)。
三.C++内存管理方式
由于C++兼容C语言,C语言内存管理方式可以继续在C++中使用。但是有的地方用C语言的方法会比较麻烦,于是C++提出了一种属于自己的内存管理方式:通过new和delete操作符进行动态内存管理。
3.1 new/delete操作内置类型
#include<iostream>
using namespace std;
int main(){
//在堆上动态申请一个int类型大小空间
int *p1 = new int;
//在堆上动态申请一个int类型大小空间,并初始化为10
int *p2 = new int(10);
//在堆上申请3个int类型大小的空间,相当于一个动态数组
int *p3 = new int[3];
//释放
delete p1;
delete p2;
delete[] p3;
return 0;
}
注意:
- 申请连续多个内置类型的空间(动态数组)时,释放在delete后加[],不需要加数字。
- 不存在 int *p=new int[3](10)这种形式。
3.2 new和delete操作自定义类型 ![](https://i-blog.csdnimg.cn/blog_migrate/7f458547ad7f8d37cd1264f44029fab7.png)
用C语言malloc申请自定义类型空间:
通过上面两幅图可以发现,用new和delete操作自定义类型时不仅会开辟空间,而且会自动调用自定义类型的构造函数,delete会自定调用析构函数,而malloc/calloc/realloc和free不会调用。
所以我们就知道,C语言中已经有了malloc/calloc/realloc和free申请和释放空间,C++也可以用,为什么还需要new和delete了。建议在C++中使用new和delete。
四.operator new和operator delete函数
new和delete是用户进行动态内存申请和释放的操作符,而operator new和operator delete是系统提供的全局函数,new底层就是通过调用operator new全局函数来申请空间,delete底层通过operator delete全局函数来释放空间。
operator new是通过malloc来申请空间,当malloc申请空间成功直接返回地址,如果申请空间失败返回NULL,但是operator new如果申请空间失败则会抛异常(简单知道,后面学习了解释)。
operator delete是通过free来释放空间的。
4.1用法:
operator new/operator delete用法和malloc/free用法一样,并且不会调用构造函数或析构函数,只是operator new申请失败会抛异常。
#include<iostream>
#include<Windows.h>
using namespace std;
class Test{
public:
Test(){
cout << "构造函数" << endl;
}
~Test(){
cout << "析构函数" << endl;
}
};
int main(){
int *p = (int *)operator new(sizeof(int));
operator delete(p);
Test *p1 = (Test *)operator new(sizeof(Test));
operator delete(p1);
return 0;
}
malloc/operator new/new的区别
free/operator delete/delete区别
五.new和delete的实现原理
- 内置类型
如果申请的是内置类型的空间,new和malloc,delete和free功能上类似,不同的是用法上new和delete申请和释放的是单个元素的空间,new[]和delete[]释放的是连续空间,并且new空间申请失败会抛异常,malloc是返回空。
- 自定义类型
new原理是
- 调用operator new申请空间
- 在申请的空间上执行构造函数。
delete的原理是
- 在空间上调用析构函数完成对象资源清理工作
- 调用operator delete完成空间的释放。
new 类型[]原理
- 调用operator new[]函数,在operator new[]中实际调用operator new完成N个对象的空间申请。
- 在再申请的空间上执行N次构造函数。
delete[]原理
- 再要释放对象的空间执行N次析构函数的调用
- 调用operator delete[]函数释放空间,实际operator delete[]中调用了N次operator delete来对N个对象进行空间释放。
六.malloc/free和new/delete区别
共同点:都是从堆上申请空间并且需要用户手动释放
不同点:
- malloc和free是函数,new和delete是操作符。
- malloc申请空间不能初始化,new可以初始化。
- malloc参数传字节数,需要用户计算,返回值为void *需要强转。new后面跟申请空间类型,返回值为类型的指针。
- malloc申请失败返回值为NULL,所以需要进行判定。new申请失败是抛异常。
- 针对自定义类型,malloc/free只是申请和释放空间,而new和delete不仅会申请和释放空间,还会调用自定义类型的构造和析构函数。
七.内存泄漏
7.1定义和危害
定义:内存泄漏指因为疏忽或者错误导致动态申请的空间不使用后没有释放的情况。内存泄漏并不是内存物理上的消失,而是应用程序动态开辟某段内存后,失去了对该内存的控制。
危害:内存泄漏对短期运行程序并不会产生很大的影响,因为进程结束了,资源就被释放了。对于长期运行的程序出现内存泄漏,影响很大,如操作系统,后台服务等,出现内存泄漏导致响应越来越慢,最终卡死。
7.2如何避免
1.事先预防。如智能指针。
2.事后差错。利用检测工具。
3.养成良好的编码习惯。