operator new 和operator delete函数

本质来说,operator new函数就是对malloc函数的封装,operator delete函数就是对free函数的封装。

申请空间所使用的函数,new和malloc的区别之一,就是:

new失败后会抛出异常,而malloc失败则会直接返回零。

原因如下:

new在底层调用operator new全局函数来申请空间,delect在底层通过operator delete 全局函数来释放空间。

operator new: 

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 delect:

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来释放空间。

下面采用反汇编来看一下new到底做了哪些事:

申请空间operator new + 构造函数

关于delete的坑点:

class A
{
public:
	A()
	{
		cout << "A()" << endl;
	}
private:
	int _a;
};
int main()
{
	A* a = new A[10];
	delete a;
	return 0;
}

运行结果:无报错

下面再给A类添加一个析构函数:

class A
{
public:
	A()
	{
		cout << "A()" << endl;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
private:
	int _a;
};
int main()
{
	A* a = new A[10];
	delete a;
	return 0;
}

运行结果:程序出错

原因:

如果自定义了析构函数,那么编译器不会优化,必须调用析构函数。

A* a = new A[10];

编译器除了会申请10*4的空间,还会额外申请4字节的空间,用来存储申请空间的数量。

如下图所示:

如果直接进行delete,那么指针的位置并不是这个空间的初始位置(因为释放空间不能部分部分的释放),所以会报错。

如果没有定义析构函数,使用编译器生成的析构函数。此时如果编译器发现自生成的析构函数并没有什么实际的工作量,则会优化,不会额外申请4字节的空间,直接delete时指针位置则不会报错。

最保险的delete方式:delete[]

class A
{
public:
	A()
	{
		cout << "A()" << endl;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
private:
	int _a;
};
int main()
{
	A* a = new A[10];
	delete []a;
	return 0;
}

虽然没有写调用几次析构函数,但是编译器可以通过指针偏移,获取申请空间的个数,由此可知调

用析构函数的次数,进行释放空间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值