前言
我们先来回顾一下C语言的内存管理
内存分为这几个段:
栈区:非静态的局部变量都是存在栈区的,它是向下增长的。
堆区:用于程序运行时动态内存分配,它是向上增长的。
数据段:存在全局变量和静态变量。
代码段:可执行代码、常量。
而在堆区动态内存开辟的函数有malloc、calloc、realloc。
malloc和calloc的区别在于,前者开辟空间不初始化,而后者会初始化为0.
realloc是扩容。
C++是兼容C语言的,所以,它们两个的内存管理是差不多的。
new关键字
在C++中搞出一套新的动态内存开辟的方式:new
先说明一点,在C语言中malloc、calloc、realloc是函数,需要包头文件的,而new是关键字,直接用就可以,方式如下:
#include<iostream>
using namespace std;
int main()
{
int* a = new int;//从堆区开辟4个字节的空间
return 0;
}
开辟出来的空间里里面的值是未定义的,是随机值,我们可以在开辟孔家的时候就给它初始化:
#include<iostream>
using namespace std;
int main()
{
int* a = new int(1);
return 0;
}
也可以开辟数组,并且初始化:
#include<iostream>
using namespace std;
int main()
{
int* a = new int(1);
int* arr = new int[10]{ 0 };
return 0;
}

delete关键字
C语言有free来释放空间,C++用的就是delete来释放空间,普通变量直接用delete,数组就需要在后面加上[]:
int main()
{
int* a = new int(1);
int* arr = new int[10]{ 0 };
delete a;
delete[] arr;
return 0;
}
那如果我用new开辟的空间,能用free来释放吗,或者说malloc开辟的空间,能用delete释放吗?
答案是:分情况。
如果是下面这种情况,也是没问题的
int main()
{
int* arr = (int*)malloc(sizeof(int));
if (arr == nullptr)
{
perror("malloc fail");
exit(-1);
}
delete arr;
return 0;
}
只不过编译器会报出警告:

但是有一种情况会出问题:
class Stack
{
public:
Stack(int size = 0,int capacity = 0)
{
arr = (int*)malloc(sizeof(int) * 4);
if (arr == nullptr)
{
perror("malloc fail");
exit(-1);
}
capacity = 4;
}
~Stack()
{
free(arr);
arr = nullptr;
cout << "资源已清理" << endl;
sz = capacity = 0;
}
private:
int* arr;
int sz;
int capacity;
};
int main()
{
Stack* st = new Stack;
free(st);
return 0;
}
这是一个栈类,里面动态开辟了一个数组,然后我们new一个栈的对象,最后用free来释放空间,free此时释放的空间是栈类实例化出来的对象的,而对象里面开辟的空间没有释放,会造成内存泄漏。
调试也可以看出,释放空间并没有调用栈这个类的析构函数

其实,关于new和delete的使用还有一点没有说明:
new:如果new的类型是自定义类型,会调用它的构造函数
delete:释放空间也是如此,会自动调用它的析构函数
还有一点要说明:
class A
{
private:
int a;
};
int main()
{
A* a = new A[10];
free(A);
return 0;
}
上面这个代码是直接编译不通过,说是不允许使用类型名,还有一点原因:
其实new在开辟空间得时候会在前面多开4个字节的空间,这4个字节的空间用来存储一共要调用多少次析构函数的次数

如果直接用free,其实释放的位置错了,所以会直接报错
如果用delete[] 来释放空间,它会自动往前面挪4个字节,然后解引用,就会知道要调用10次析构函数,然后释放后面的空间。
总结:最好还是配套使用,即malloc出来的空间就用free,new出来的就用delete。
operator new和operator delete
它们不是运算符重载,它们是定义在标准库中的,它们是干嘛的呢?
其实,它们就是对malloc和free进行封装:
operator new:对malloc进行封装,只是malloc开辟空间失败是返回空,而operator new开辟失败是抛出异常。
operator delete:同理,对free进行封装。
所以,operator delete最终还是用free来释放。
new、delete实现原理
new是会先调用operator new申请空间,如果申请失败抛出异常,否则,继续调用构造函数。
而delete是先调用析构函数、再调用operator delete释放空间。
上面的过程只是针对自定义类型,对于内置类型,和C语言的malloc、free没什么区别,毕竟new的底层还是用的malloc,delete的底层还是用的free。
本文介绍了C++中的内存管理,包括new和delete关键字的使用,以及operatornew和operatordelete的作用。new用于动态内存分配,会调用构造函数,而delete则负责释放内存并调用析构函数。operatornew和operatordelete是对malloc和free的封装,提供异常处理。文章强调了new和delete配套使用的重要性,避免内存泄漏,并指出直接使用malloc/free可能存在的问题。
6880

被折叠的 条评论
为什么被折叠?



