new的实现以及模拟set_new_handler机制
typedef void(*new_handler)( );
class x
{
public:
static new_handler set_new_handler(new_handler p);
static void* operator new(size_t size);
private:
static new_handler currenthandler;
};
new_handler x::currenthandler = 0;
new_handler x::set_new_handler(new_handler p)
{
new_handler oldhandler = currenthandler;
currenthandler = p;
return oldhandler;
}
void* x::operator new(size_t size)
{
if (size = 0) {
size = 1;
}
while (1) {
void* result = malloc(size);
if (result != NULL)
return result; //开辟成功,直接返回
new_handler globalhandler = set_new_handler(0); //把原先的保存
set_new_handler(globalhandler);
if (globalhandler)
(*globalhandler)();
else
throw std::bad_alloc();
}
}
重点是operator new
几乎很多现代的编译器默认都会这么做:
当我们int *p = new int[0];我们发现竟然成功。这是因为我们new默认如果参数是0的话,会以最小值分配
所以有
if (size = 0) {
size = 1;
}
好了,当我们new分配到内存时,会返回我们分配的指针
void* result = malloc(size);
if (result != NULL)
return result; //开辟成功,直接返回
我们这里主要想说的是分配失败时,究竟编译器会做什么工作?
第一种情况:若然我们设置了set_new_handler函数,那么如何分配内存失败,就会去执行set_new_handler设置了的函数
我们可以看看set_new_handler大致是怎么实现的
new_handler x::set_new_handler(new_handler p)
{
new_handler oldhandler = currenthandler;
currenthandler = p;
return oldhandler;
}
这个函数大致就是把新的设置进去,而把旧的返回出去,方便我们回收
回到operator new代码
new_handler globalhandler = set_new_handler(0); //把原先的保存
set_new_handler(globalhandler);
if (globalhandler)
(*globalhandler)();
else
throw std::bad_alloc();
我们先获取set_new_handler里面的函数指针
去判断这个指针是否为NULL
若不为NULL,那就即是我们设置了set_new_handler
那么就去执行我们的set_new_handler
一般来说,set_new_handler该做的就是把一些我们没用的free掉,然后重新地去malloc
所以这里被写成了while(1)
第二种情况:
我们根本就没有设置set_new_handler
那么operator new就会抛出一个标准库的异常std::bad_alloc();
所以,我们若然抛出std::bad_alloc();而我们又不去处理,那么将会引出一个BUG
就是程序直接就死掉了
所以,我们应该在不同情况下去灵活地处理不同的事件
第一种方法:set_new_handler
第二种方法:try catch
第三种方法:重载operator new,重载我们的new操作(这个操作可移植性最高,因为STL在不同编译环境下都不同)