C/C++内存分布
- 栈:非静态局部变量,函数参数,返回值等,栈是向下增长的
- 内存映射段:装载一个共享的动态内存库
- 堆:用于程序运行时动态内存分配,可以向上增长
- 数据段:存储全局变量和静态数据
- 代码段:可执行的代码、只读常量
C语言中内存管理方式
malloc:只进行空间申请,不进行初始化。
calloc:进行空间申请+零初始化。
realloc:第一个参数为nullptr/NULL,功能等价于malloc。
int* ptr=(int*)realloc(nullptr, sizeoff(int));
调整空间大小:1.直接原地调整大小 2.重新开空间:重新申请空间,内容拷贝,释放原有空间。
int* ptr2=(int*)realloc(ptr, sizeoff(int)*4);
传入realloc中的空间后需不需要显式释放,会导致二次释放的问题。
new / delete 操作内置类型
申请空间
int* ptr1 = new int;//动态申请一个int类型的空间
int* ptr2 = new int(10);//动态申请一个int类型的空间并初始化为10
int* ptr3 = new[10];//动态申请10个int类型的空间
- 单个类型的空间:new + 类型
- 连续空间:new + 类型[个数]
- 单个类型空间申请 + 初始化:new + 类型(初始值)
释放空间:
delete ptr1;
delete ptr2;
delete[] ptr3;
- 单个空间delete 指针
- 连续空间:delete[ ] 指针
new / delete操作自定义类型
动态创建自定义类型对象:
class Date
{
public:
Date(int year)
{
_year = year;
}
private:
int _year;
};
void test()
{//new:动态开空间 + 调用构造函数初始化
Date* pd1 = new Date(2020);
Date* pd2 = new Date(2019);//调用默认构造:无参构造,全缺省构造
Date* pd3 = new Date[10];
}
- 申请单个空间:new 自定义类型(参数列表),调用构造函数初始化
- 申请连续空间:new 自定义类型[个数] , 自动调用默认构造进行初始化,如果没有则编译器报错
释放自定义类型的空间:
delete pd1;//调用一次析构 + 释放空间
delete pd2;//调用一次析构 + 释放空间
delete[] pd3;//调用十次析构,因为Date[10] + 释放空间
- delete:调用析构函数清理资源 + 释放空间
- 连续空间:调用N次析构+释放空间
申请和释放操作匹配使用:malloc free, new delete, new[ ]delete[ ]。
operator new 与 operator delete函数
void* operator new(size_t n)
- 不是运算符重载函数,而是一个全局变量。
- 使用方式和malloc类似
- 封装malloc + 异常处理机制
new的执行过程:operator new–>mallow–>构造函数
申请失败会抛出bad_alloc类型异常
void operator delete(void* ptr)
- 不是运算符重载函数
- 使用方式和free类似
- 封装free
只有自定义类型才会调用构造函数和析构函数
delete的执行过程(自定义类型):析构–> operator delete–>free
operator new 与 operator delete的类专属重载
struct Node
{
public:
Node()
{
cout << "Node()" << endl;
}
void operator new(int data)
{
void* p = nullptr;
p = allocator<Node>().allocate(1);
cout << "mem pool allocate" << endl;
return p;
}
void operator delete(Node* ptr)
{
allocator<Node>().deallocate((Node*)ptr, 1);
cout << "mem pool deallocate" << endl;
}
private:
int _data;
Node* _next;
};
void test()
{
Node* np1 = new Node;
Node* np2 = new Node[10];
delete np1;
delete[] np2;
}
new / delete 原理
new / delete: 内置类型
- new : operator new --> malloc 失败抛异常
- delete : operator delete --> free
- new [] : operator new[] --> operator new --> malloc
- delete [] : operator delete[] – > operator delete --> free
- 和malloc区别:new空间申请失败抛异常,malloc空间申请失败返回空指针
- 和free区别:没有本质区别,delete封装了free操作
new / delete: 自定义类型
- new : operator new --> malloc --> 构造函数 失败抛异常
- delete : 析构函数 --> operator delete --> free
- new [] : operator new[] --> operator new --> malloc --> N此构造函数
- delete [] : N次析构函数 --> operator delete[] – > operator delete --> free
- 和malloc区别:new空间申请失败抛异常,malloc空间申请失败返回空指针,new会调用自定义类型的构造函数,完成初始化,malloc不会。
- 和free区别:delete会调用自定义类型的析构函数,完成资源清理的工作,free不会
malloc/free和new/delete的区别
malloc/free和new/delete
共同点是:都是从堆上申请空间,并且需要用户手动释放。
不同的地方是:
- malloc和free是函数,new和delete是操作符。
- malloc申请的空间不会初始化,new可以初始化。
- malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可。
- malloc的返回值为void*,在使用时必须强转,new不需要,因为new后跟的是空间的类型。
- malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常。
- 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理。
new定位表达式:new(地址)类型(参数列表)
在已经开好的空间上显示调用构造函数
new(pd)Date(2030);
Date* pd = (Date*)malloc(sizeof(Date));
new (pd)Date(2030);
Date* pd2 = (Date*)malloc(sizeof(Date));
new (pd2)Date;