目录
C++动态内存管理
内置类型的动态内存管理
自定义类型的动态内存管理
new和delete的实现原理
new和malloc、delete和free的异同
new的其他用法:定位new
C语言动态内存管理<-点这里
C++动态内存管理
因为C语言中的管理方式使用起来不方便而且有些情况下无法解决问题,C++通过new、delete关键字进行动态内存管理,delete和new必须配套使用,不能new开辟空间使用free释放空间。
内置类型的动态内存管理
//动态申请1个int类型的空间
int* p1 = new int;
delete p1;//动态申请1个int类型的空间并初始化为10
int* p2 = new int(10);
delete p2;//动态申请10个int类型的空间
int* p3 = new int[10];
delete[] p3;//动态申请10个int类型的空间并初始化
int* p4 = new int[10]{1,2,3,4,5,6,7,8,9,10};
delete[] p4;//动态申请一个10行10列的二维数组
//int(*p)[n] 是一个数组指针,该数组有10个int类元素
int(*arr1)[10] = new int[10][10];
delete[] arr1;//用二级指针模拟实现10行10列的二维数组
//内存开辟
int** arr2 = new int*[10];
for (int i = 0;i < 10;i++)
{arr2[i] = new int[10];
}
//空间释放
for (int i = 0;i < 10;i++)
{delete[] arr2[i];
}
delete[] arr2;
申请和释放单个元素的空间使用new和delete,申请和释放连续的空间使用new[]和delete[]
自定义类型的动态内存管理
new为自定义类型分配空间后,会调用构造函数,delete释放自定义类型空间前会调用析构函数
class Stack
{
private:int* _arr;int _capacity;int _top;
public:Stack():_capacity(4),_top(0){_arr = new int[4];}Stack(int capacity):_capacity(capacity),_top(0){_arr = new int[capacity];}~Stack(){delete[] _arr;}
};int main()
{Stack* st1 = new Stack(10);delete st1;Stack* st2 = new Stack[3];delete[] st2;Stack* st3 = new Stack[3]{ 5,2,4 };delete[] st3;Stack* st4 = new Stack[3]{ Stack(5),Stack(2),Stack(4) };delete[] st4;
}
注意:自定义类型数组初始化有多种方法,如果有单参构造函数或者除了缺省参数只有一个参数的构造函数,数组初始化可以直接用该参数类型的值,直接放到{ }内初始化,因为它会自动转换成对象来初始化数组;还可以用匿名对象初始化。
new和delete的实现原理
因为malloc和calloc的功能是开辟空间,如果开辟空间失败返回0。但是对于C++面向对象的语言来说,往往遇到问题要抛异常,所以会用operator new来封装malloc,以达到抛异常的功能。operator delete也是如此。
new的原理
1. 调用operator new函数申请空间
2. 在申请的空间上执行构造函数,完成对象的构造
delete的原理
1. 在空间上执行析构函数,完成对象中资源的清理工作
2. 调用operator delete函数释放对象的空间
new T[N]的原理
1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对
象空间的申请
2. 在申请的空间上执行N次构造函数
delete[]的原理
1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释
放空间
new和malloc、delete和free的异同
相同点:new和malloc、delete和free都是从堆上申请空间,都需要对空间手动释放
不同点:
- (特性)new/delete是关键字,malloc/free是函数
- (特性)malloc使用时需要计算空间大小,new会根据数据类型自动计算,如果有多个数据直接在[ ]指定数量即可
- (特性)malloc的返回值是void*,使用时需要强制类型转换,而new不需要。
- (特性)malloc申请空间失败返回NULL,而new需要捕获异常
- (功能)malloc申请的空间不会初始化,new申请的空间可以初始化
- (最重要)(功能)malloc/free只会开辟和释放空间,而new会先调用operator new开辟空间再调用构造函数初始化,delete会先调用析构函数完成空间资源的清理再调用operator delete释放空间。
new的其他用法:定位new
作用:在已经开辟好的一块空间调用构造函数初始化
格式:new(address)custom type(initial list)或者new(address)basic type(initial list)
address是开辟的空间的地址;
custom type表示自定义类型;
initial list表示自定义类型的初始化列表;
basic type表示基本数据类型
使用场景:
定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如
果是自定义类型的对象,需要使用new的定义表达式进行显示调构造函数进行初始化。
优势:
内存的申请和释放有一定的开销,遇到需要频繁申请释放内存的情况时,可以一次性开好空间,使用定位new调用构造函数初始化,可以提高效率。
class Date
{friend ostream& operator<<(ostream& _cout, const Date& d);
private:int _year;int _month;int _day;
public:Date(int year = 2023, int month = 1, int day = 1):_year(year),_month(month),_day(day){}~Date(){}
};//流插入运算符重载
ostream& operator<<(ostream& _cout,const Date& d)
{_cout << d._year << "-" << d._month << "-" << d._day;return _cout;
}int main()
{//基本数据类型int i = 5;int* p1 = (int*)malloc(sizeof(int));new(p1)int(10);cout << *p1 << endl;//10new(p1)int(i);cout << *p1 << endl;//5free(p1);//自定义数据类型Date* p2 = (Date*)malloc(sizeof(Date));new(p2)Date();//无参时,初始化的()可加可不加cout << *p2 << endl;//2023-1-1new(p2)Date(2023, 5, 20);cout << *p2 << endl;//2023-5-20p2->~Date();free(p2);
}