new和delete是用于动态内存管理的运算符,用于在堆上分配和释放内存。new运算符用于在堆上分配内存,并调用对象的构造函数进行初始化。
注意
new和delete操作符通过调用 operator new与operator delete 全局函数实现功能
可以重载全局的operator new和operator delete函数,但是不能重载new和delete运算符,注意“operator new”是一个函数的名称,而不是对new进行了重载的意思 ;
operator new和operator delete函数的内部逻辑大致遵从以下形式/逻辑:
cpp
void* operator new(std::size_t size)
{
void* ptr = std::malloc(size); // 使用标准库函数 malloc 分配内存
if (ptr == nullptr) // 内存分配失败
{
throw std::bad_alloc(); // 抛出 bad_alloc 异常
}
return ptr;
}
void operator delete(void* ptr)
{
// 自定义内存释放逻辑
// ...
free(ptr);
}
malloc/free和new/delete的共同点是:都是从堆上申请空间,并且需要用户手动释放。不同的地方是:
new[] / delete[] = operator new[] / operator delete[] + 多次构造函数
operator new[] / operator delete[] = 多次调用operator delete / operator new
operator new 成功:
operator new = malloc函数 / 自定义重载操作 + malloc函数
operator new 失败:
operator new = 抛异常)/ 抛异常 + 自定义重载操作
operator delet = free函数 / 自定义重载操作 + free函数
new = operator new 函数 + 构造函数 (注意先后顺序)
delete = 析构函数 + operator delet 函数 (注意先后顺序)
new (pointer) Type [initializer];
pointer是一个指向已分配内存的指针,Type是要构造的对象类型,initializer是可选的初始化列表。
定位new表达式(placement new)是一种特殊的new表达式,用于在已分配的内存地址上构造对象。它允许我们在指定的内存位置上创建对象,而不是在堆上动态分配内存。
使用:
class A
{
public:
A(int a = 0)
: _a(a)
{
cout << "A():" << this << endl;
}
~A()
{
cout << "~A():" << this << endl;
}
private:
int _a;
};
int main()
{
/* p1现在指向的只不过是与A对象相同大小的一段空间,
还不能算是一个对象,因为构造函数没有执行*/
A* p1 = (A*)malloc(sizeof(A));
// !!!!!!!!!!!!!!!!!!!!!!
// 定位new/replacement new
// 注意:如果A类的构造函数有参数时,此处需要传参
new(p1)A;
p1->~A();
free(p1);
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
A* p2 = (A*)operator new(sizeof(A));
new(p2)A(10);
p2->~A();
operator delete(p2);
return 0;
}
内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。
内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死。
堆内存泄漏(Heap leak)
堆内存指的是程序执行中依据须要分配通过malloc / calloc / realloc / new等从堆中分配的一块内存,用完后必须通过调用相应的 free或者delete 删掉。假设程序的设计错误导致这部分内存没有被释放,那么以后这部分空间将无法再被使用,就会产生Heap Leak。
系统资源泄漏
指程序使用系统分配的资源,比方套接字、文件描述符、管道等没有使用对应的函数释放掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定。
注 : 内存泄漏检测工具只是有概率查处错误 。