今天来分享C++动态内存管理相关知识,闲言勿谈,直接上干货。
1. 动态内存的开辟和销毁(new和delete)
(1)前置知识:我们知道c语言有malloc和calloc和realloc三个函数可以进行动态的开辟内存,那么它们有什么区别呢?首先是malloc,malloc表示直接在堆上动态开辟内存空间,返回void*,而calloc不仅可以直接在堆上动态开辟内存空间,还会把开辟空间的内容初始化为0,calloc返回的也是void*,realloc是在原有的空间的基础上进行扩容,也是返回void*.c语言虽然有三个动态开辟内存的函数,但在某些场景下不适用,同时用起来也比较麻烦,所以c++引入了一个new操作符进行动态开辟内存,delete操作符进行销毁开辟的内存,那么接下来我们看看new的用法吧。
(2)new和delete用法
new和delete操作符对内置类型进行开辟空间
new和malloc对于内置类型开辟空间,功能都差不多。
int main()
{
//表示在堆上申请一个int空间
int* p1 = new int;
delete p1;
//表示在堆上申请一个int空间并初始化为4
int* p2 = new int(4);
delete p2;
//表示在堆上申请3个int空间
int* p3 = new int[3];
delete[] p3;
return 0;
}
new和delete操作符对自定义类型进行开辟空间
我们来看看new和malloc对于自定义类型开辟空间的不同之处。
class A
{
public:
A(int a = 0)
: _a(a)
{
cout << "A():" << this << endl;
}
~A()
{
cout << "~A():" << this << endl;
}
private:
int _a;
};
int main()
{
A* p1 = (A*)malloc(sizeof(A));
A* p2 = new A;
free(p1);
delete p2;
return 0;
}
我们来看看这个代码运行的结果
咋出现了调用构造函数和析构函数呢?是谁调用的呢?
我们把malloc和free的函数进行注释掉,如果还调用构造函数和析构函数,那么证明是new和delete调用的构造函数和析构函数。
class A
{
public:
A(int a = 0)
: _a(a)
{
cout << "A():" << this << endl;
}
~A()
{
cout << "~A():" << this << endl;
}
private:
int _a;
};
int main()
{
/*A* p1 = (A*)malloc(sizeof(A));*/
A* p2 = new A;
//free(p1);
delete p2;
return 0;
}
还是调用了构造函数和析构函数,现在我们就清楚了malloc函数和new操作符,free函数和delete操作符之间的区别是,new开辟空间是会调用构造函数进行初始化,delete在释放空间是会调用析构函数对对象中的资源进行清理。
(2)operator new函数和operator delete函数
我们先来看看c++标准库里面是如何实现operator new和operator delete函数的。
我们可以看到operator new和operator delete是依靠malloc和free函数实现的,该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间失败,尝试执行空间不足应对措施,如果改应对措施用户设置了,则继续申请,否则抛异常。
new和delete实现的原理
(1)对于内置类型,new和malloc功能相似,delete和free功能相似。
(1)对于自定义类型
new不仅调用operator new函数开辟空间还会调用构造函数。
delete不仅会调用operator delete函数释放空间,还会调用析构函数完成对对象资源的清理工作
总结:
1.共同点:malloc和new都是在堆上开辟空间,都需要手动释放开辟的空间
2.不同点:malloc和free是函数,new和delete是操作符(概念性质不同)
malloc开辟空间是要传需要开辟的字节数,返回的是void*;而new后跟申请对象的类型,返回的是申
请对象的类型的指针
new会调用构造函数,开辟失败会抛异常,malloc开辟失败会返回0