operator new与operator delete

196 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第9天,点击查看活动详情

💦 operator new与operator delete函数

new 和 delete 是用户进行动态内存申请和释放的操作符,operator new 和 operator delete 严格来说不是 new 和 delete 的重载 (名字确实容易误导),而是系统提供的全局库函数,new 在底层调用 operator new 全局函数来申请空间,delete 在底层通过 operator delete 全局函数来释放空间。

new A:

  1. 申请内存 —— 调用 operator new
  2. 构造函数

delete A:

  1. 析构函数
  2. 释放内存 —— 调用 operator delete

new 的反汇编 ❗ 在这里插入图片描述

❓ 为什么要去调用 operator new 而不是调用其它的呢 ❔

int main()
{
	//malloc失败返回空
	char* p1 = (char*)malloc(0xffffffff);
	if (p1 == NULL)
	{
		printf("malloc fail\n");
	}
	else
	{
		printf("malloc success:%p\n",p1);
	}
	//new失败抛异常
	char* p2 = new char[0x7fffffff];
	if (p1 == NULL)
	{
		printf("malloc fail\n");
	}
	else
	{
		printf("malloc success:%p\n", p1);
	}	
	return 0;
}

📝说明 在这里插入图片描述 因为 new 和 malloc 它们失败时,处理的方式不一样

malloc 失败了,这里的检查起作用了

new 失败了,这里的检查没起作用,还引发了一个崩溃 —— 抛异常后没有解决 在这里插入图片描述 抛异常 ❓

int main()
{
	try
	{
		char* p2 = new char[0x7fffffff];//出错,抛异常,它会跳到捕获异常的位置
	}
	catch(const exception& e)
	{
		cout << e.what() << endl;	
	}
	return 0;
}

📝说明

在这里插入图片描述

这里就可以看到 new 和 malloc 处理的方式不一样,毕竟一个是面向过程,一个是面向对象

关于什么是异常后面我们会具体学习

所以再看 new 的底层的实现,new 的底层申请内存时是不能让 malloc 去完成的,因为 malloc 失败就直接返回空了,就无法达到让它失败后抛异常的机制,所以其中就产生了 operator new

对于 delete 就不存在失败了抛异常,我们说 malloc 会失败,但没有说 free 会失败 (free 的失败是对越界的空间 free 等),free 失败就不是说抛异常或返回空这样的概念了,这种是属于比较严重的错误,它是直接中止掉程序

operator new 和 operator delete 源码 ❗

/*
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间失败,
尝试执行空 间不足应对措施,如果改应对措施用户设置了,则继续申请,否则抛异常。
*/
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
	//try to allocate size bytes
	void *p;
	while ((p = malloc(size)) == 0)
	if (_callnewh(size) == 0)
	{
		//report no memory
		//如果申请内存失败了,这里会抛出bad_alloc 类型异常
		static const std::bad_alloc nomem;
		_RAISE(nomem);
	}
	return (p);
}
/*
operator delete: 该函数最终是通过free来释放空间的
*/
void operator delete(void *pUserData)
{
	_CrtMemBlockHeader * pHead;
	RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
	if (pUserData == NULL)
		return;
	_mlock(_HEAP_LOCK); /* block other threads */
	__TRY
	/* get a pointer to memory block header */
	pHead = pHdr(pUserData);
	/* verify block type */
	_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
	_free_dbg( pUserData, pHead->nBlockUse );
	__FINALLY
	_munlock(_HEAP_LOCK); /* release other threads */
	__END_TRY_FINALLY
	return;
}
/*
free的实现
*/
#define free(p) _free_dbg(p, _NORMAL_BLOCK)

📝说明

通过上述两个全局函数的实现知道,operator new 实际也是通过 malloc 来申请空间,如果 malloc 申请空间 成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异 常。operator delete 最终是通过 free 来释放空间的。

operator new 就是对 malloc 的封装,目的就是如果申请内存失败了抛异常:

  • new = 封装 malloc + 失败抛异常 + 调用构造函数

operator delete 就是对 free 的封装,目的主要还是和 operator new 对应起来

  • delete = 调用析构函数 + operator delete

这里具体后面也会学习

直接使用 operator new 和 operator delete ❓ 在这里插入图片描述

class A
{
public:
	A(int a = 0)
		: _a(a)
	{
		cout << "A()" << endl;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
private:
	int _a;
};
int main()
{
	//调用构造和析构
	A* p1 = new A;
	delete p1;

	//不会调用构造和析构
	A*p2 = (A*)operator new(sizeof(A));
	operator delete(p2);
	
	return 0;
}

📝说明

我们直接使用 operator new 和 operator delete 本质上和 malloc 和 free 没有区别

所以平时我们也几乎不会用 operator new 和 operator delete