C++动态内存分配
operator new/delete函数
new和delete是用户进行动态内存申请和释放的操作符, operator new和operator delete是系统提供的全局函数.
new 在底层调用operator new全局函数申请空间
operator new 函数实际通过malloc申请空间, 当malloc申请空间成功的时候直接返回; 如果申请空间失败, 会尝试执行空间不足的应对措施, 如果该应对措施用户设置了, 就会继续申请, 否则就会抛异常
deldete 在底层通过operator delete全局函数来释放空间
operator delete函数最终是通过free来释放空间的
new和delete实现原理
内置类型
如果申请的是内置类型的空间, new和malloc, delete和free基本类似
但是不同的地方是: new和delete申请和释放的是单个元素的空间
new[]和delete[]申请的是连续空间, 而且new在申请失败时会抛异常, malloc会返回NULL.
自定义类型
new的原理
调用operator new函数申请空间
在申请的空间上执行构造函数, 完成对象的构造
delete原理
在空间上执行析构函数, 完成对象中资源的清理工作
调用operator delete函数释放对象的空间
new T[N]的原理
调用operator new[]函数, 在operator new[]中实际调用operator new函数完成N个对象空间的申请
在申请的空间上执行N次构造函数
delete[] 的原理
在释放的对象空间上执行N次析构函数, 完成N个对象中资源的清理
调用operator delete[]释放空间, 实际在operator delete[]中调用operator delete来释放空间
定位new表达式
定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象
使用格式
new(address) T或者new(address) T(类型初始化列表)
address必须是一个指针
使用场景
定位new表达式在实际中一般是配合内存池使用, 因为内存池分配出的内存没有初始化, 所以如果是自定义类型的对象, 需要使用new的定义表达式进行显式调用构造函数进行初始化.
代码示例:
#include <iostream>
using namespace std;
class Test
{
int m_data;
public:
Test() :
m_data(0)
{
cout << "Test():" << this << endl;
}
~Test()
{
cout << "~Test():" << this << endl;
}
};
int main()
{
//pt指向的是与Test对象相同大小的一块空间, 还不能算是一个对象, 因为构造函数没有执行
Test * pt = (Test*)malloc(sizeof(Test));
new(pt) Test;//如果Test的构造函数有参数时, 这里还需要传参
system("pause");
return 0;
}
new定位表达式释放是否有必要?
通过new定位表达式申请的空间实际并没有开辟新的空间, 所以不需要通过delete释放, 如果要调用析构函数, 可以使用显式调用的方式
例如: pt->~Test();