内存管理
1.C/C++内存分布
1.栈区从高地址向低地址增长,存放非静态局部变量,函数参数等
2.堆区从低地址到高地址增长,存放malloc,new出来的变量。
3.数据段存放全局变量和静态变量
4.代码段存放只读常亮,可执行代码。
2.从C语言的内存管理引入
C语言动态内存管理: link.
这里面是博主对于c语言出现的动态开辟内存管理的总结,包括基本使用和常见错误
3.C++内存管理
在c++中我们系统定义了2个关键词来用于对内存的管理。
针对内置类型的基本操作
注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[ ]和delete[ ]
管理对象
//申请空间
int* ptr = new int;
//申请空间并初始化
int* ptr2 = new int(1);
delete ptr;
delete ptr2;
管理对象数组
//申请大小为4*10的连续空间
int* arr = new int[10];
//c++98不允许连续空间初始化
//c++11后支持
// int *arr =new[10](1);(是错误代码)
delete[] arr;
针对自定义类型的基本操作
相比于内置类型,自定义类型的new和delete功能更丰富:
new会调用构造函数去初始化(new仅仅是对空间的申请)
delete会调用析构函数去清理空间
#include <iostream>
using namespace std;
class Test
{
public:
Test()
: _data(0)
{
cout << "Test():" << this << endl;
}
~Test()
{
cout << "~Test():" << this << endl;
}
private:
int _data;
};
void Test2()
{
// 申请单个Test类型的空间
Test* p1 = (Test*)malloc(sizeof(Test));
free(p1);
// 申请10个Test类型的空间
Test* p2 = (Test*)malloc(sizeof(Test) * 10);
free(p2);
}
int main()
{
Test* t = new Test;
delete t;
return 0;
}
可以看出他们的构造函数和析构函数都调用了,并且是一个物理空间。
注意:
1.必须要有默认构造才可以进行动态空间的开辟。
operator new和operator delete
1.new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。
2.operator new 实际也是通过malloc来申请空间,如果malloc申请空间
成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常。operator delete 最终是通过free来释放空间的。
可以理解为operator new就是封装了malloc和异常处理机制。
new&delete实现原理
void test1(){
//内置类型
int* ptr = new int;
//new->operator new->malloc
delete ptr;
//delete->operator delete->free
int* ptr1 = new int[10];
//new[]-> operator new[]-> operator new->malloc
delete[] ptr1;
//delete[]->operator delete[]->operator delete->free
//自定义类型
Test* t1 = new Test;
//new->operator new->malloc->构造
delete t1;
//delete->析构->operator delete->free
Test* t2 = new Test[10];
//new[]->operator new[]->operator new->malloc->10构造
delete t2;
//delete[]->10析构->operator delete[]->operator delete->free
}
malloc/free和new/delete区别
- malloc和free是函数,new和delete是操作符
- malloc申请的空间不会初始化,new可以初始化
- malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可
- malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型
- malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常
- 申请自定义类型对象时,new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理