内存操作符
C++内存管理是兼容C语言的,但是由于C++中有类的存在,所以C语言的内存申请就会存在一定的不足,所以我们引入了新的操作符new和delete
new
动态申请一块内存,开辟失败的话会抛异常。
int main()
{
int* p1 = new int; // 不会初始化
int* p1 = new int(10); // 申请一个int,初始化10
int* p3 = new int[10]; // 申请10个int的数组
int* p4 = new int[10] {1, 2, 3, 4};//申请10个int的数组,并前几个初始化为1,2,3,4
return 0;
}
delete
内存回收的操作符,与new配对使用。
void Test()
{
// 动态申请一个int类型的空间
int* ptr4 = new int;
// 动态申请一个int类型的空间并初始化为10
int* ptr5 = new int(10);
// 动态申请10个int类型的空间
int* ptr6 = new int[3];
delete ptr4;
delete ptr5;
delete[] ptr6;//释放连续的空间
}
两个关键字的底层
operator new和operator delete
new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。
所以上面的图,new开辟的空间是在堆上面,而不是在栈上面
,operator new 实际也是通过malloc来申请空间,如果malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常。operator delete 最终是通过free来释放空间的。
所以说,new实际上是operator new 对malloc的封装,开辟失败就抛异常;而delete是operator delete对free的封装。
new与delete注意事项
new与delete对于自定义类型会调用构造和析构函数,对于内置类型和malloc与free一致
不要交叉使用new、delete、malloc、free。
用new开辟的空间,当涉及到调用析构函数来销毁空间的时候,不使用delete而使用free大概率会导致报错。
因为delete会先使用析构函数,之后才会释放空间,直接使用free会导致没有析构自定义类型里面申请的空间导致内存泄露
其次,VS中delete销毁连续的数组空间是会在前面开辟出一小块空间,来存储后面一共开出了几个空间的数量,是为了调用析构函数来进行销毁,不调用析构是不会多开辟出那一部分空间的
所以一定要配对使用。
new和delete的实现
内置类型
如果申请的是内置类型的空间,new和malloc,delete和free基本类似,不同的地方是:
new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间,而且new在申
请空间失败时会抛异常,malloc会返回NULL。
自定义类型
new的原理
- 调用operator new函数申请空间
- 在申请的空间上执行构造函数,完成对象的构造
delete的原理
- 在空间上执行析构函数,完成对象中资源的清理工作
- 调用operator delete函数释放对象的空间
new T[N]的原理
- 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请
- 在申请的空间上执行N次构造函数
delete[]的原理
- 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
- 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释 放空间