1.回顾c语言中的动态内存管理
在c语言中,我们想要动态开辟一段空间,需要使用malloc,calloc,realloc几个函数
void* malloc (size_t size);
//在堆上申请size个字节的空间
void* calloc (size_t num, size_t size);
//第一个参数是元素的数目,第二个参数是每个元素的大小,实际上申请的空间大小为num*size字节,并且会初始化为0
void* realloc (void* ptr, size_t size);
//ptr是指向原来地址的指针,这个函数用于修改一个原先已经分配内存块的大小。(可以扩大,也可以缩小)
//size是修改后新空间的大小
//若果使用realloc扩容,分为原地扩容和异地扩容,如果是异地扩容,还会将原空间的元素拷贝到新空间,然后释放原空间并返回新空间的指针
当我们使用完这些空间的时候,我们要使用free函数将空间释放
2.c++中的动态内存管理
1.new和delete
在我们学习了c++之后,我们更倾向于使用new和delete进行动态内存管理。首先我们要知道new/delete是操作符,而malloc/realloc/calloc都是函数。下面我们介绍一下new/delete的使用方式
int* p1 = new int;//new一个int类型的对象,不初始化
int* p2 = new int(5);//new一个int类型的对象,初始化为5
int* p3 = new int[10];//new十个int类型的对象,不初始化
int* p4 = new int[10] {1, 2, 3, 4, 5};//new十个int类型的对象,并对前五个分别初始化为12345,后面5个初始化为0
delete p1;
delete p2;
delete[] p3;//注意释放多个对象的时候要带[]
delete[] p4;
2.new/delete操作自定义类型
如果我们申请空间用于存放内置数据类型,无论是使用new/delete还是malloc/realloc/calloc的效果都是一样的,可是如果是自定义类型,他们就有区别了,看下面的例子
class Date
{
public:
Date(int year = 0, int month = 1, int day = 1)
:_year(year)
, _month(month)
, _day(day)
{
cout << "Date(int year = 0, int month = 1, int day = 1)" << endl;
}
~Date()
{
cout << "~Date()" << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date* pd1 = (Date*)malloc(sizeof(Date));
free(pd1);
cout << "*****************" << endl;
Date* pd2 = new Date;
delete pd2;
return 0;
}
从打印结果我们可以看出,malloc/free只是单纯的申请空间,并不进行初始化,而new的时候不仅开辟空间,还调用了自定义类型的构造函数进行初始化,在delete的时候调用析构函数进行资源的清理。
3.operator new与operator delete函数
operator new与operator delete都是函数,与运算符重载没有任何关系
void* operator new (std::size_t size) throw (std::bad_alloc);
void operator delete (void* ptr) throw();
new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是系统提供的
全局函数,new在底层调用operator new全局函数来申请空间,operator new底层通过malloc申请空间。delete在底层通过operator delete全局函数来释放空间,operator delete底层调用free来释放空间。
4.malloc/free与new/delete的区别
- 前者是函数,后者是操作符
- malloc失败返回nullptr,new失败抛异常。
- 对于自定义类型,malloc只开空间,不初始化。new不仅开空间,还自动调用构造函数初始化
- 对于自定义类型,free的时候不会调用析构函数清理资源,而delete的时候会调用析构函数清理资源
- malloc申请空间要手动计算空间大小,而new只需要后面跟着类型即可。