您的位置:首页 > 运维架构

operator new之错误处理函数new_handler

2016-07-10 19:52 337 查看
就像可以用atexit来注册main的退出处理函数一样,我们也可以用std::set_new_handler来注册operator new的错误处理函数。

当operator new无法满足某一内存分配需求时,operator new会抛出异常。

但是当operator new无法满足某一内存分配需求而抛出异常之前,会先调用一个用户指定的错误处理函数,即所谓的new-handler。

即operator new无法满足内存分配需求--->(循环)调用执行用户指定的错误处理函数new-handler--->operator
new抛出异常

 

用户可以调用std::set_new_handler接口指定这个“用以处理内存不足”的函数new-handler,

new-handler是声明于<new>的一个标准程序库函数,如下所示:

namespace std {
typdef void (*new_handler)();
new_handler set_new_handler(new_handler p) throw();
}

可知:

1)new_handler是通过typedef定义出的一个指针指向函数,该函数不返回任何东西

2)set_new_handler:则是获得一个new_handler并返回一个new_handler的函数

set_new_handler函数的实现大概如下所示:

new_handler set_new_handler(new_handler p) throw
{
new_handler oldHandler = m_curHandler;
m_curHandler = p;
return oldHandler;
}

3)声明式的尾端throw()是一份异常明细,表示该函数不抛出任何异常

注:当operator new无法满足内存申请时,operator new会不断反复调用new-handler函数,直到找到足够内存。

示例如下:

#include <stdlib.h>	//for abort()
#include <iostream>
void outOfMem()
{
std::cerr<<"operator new unable to satisfy request for memory, try allocate memory again.\n";
}
int main()
{
std::set_new_handler(outOfMem );
int *buf = new int[1000000000L];
Delete []buf;
return 0;
}
测试结果如下所示:



通过以上测试可知,当operator new无法满足内存分配时,如果你通过std::set_new_handler设置了operator
new的错误处理函数new_handler后,就会重复调用new_handler函数直到找到足够的内存(如果你在new_handler内调用了abort或者exit则new_handler会只被调用一次)。

 

跟进一步得出结论,设计一个良好的new_handler函数是很重要的。

new_handler能选择以下几个处理方式中的一个方式进行处理是比较合理的,也是应该的。

处理方式1:让更多内存被使用

程序刚开始时就申请分配一大块内存,当new_handler被调用时就释放它还给程序使用。

处理方式2:安装另一个new_handler

如果new_handler1无法处理时,就在new_handler1内部调用set_new_handler设置new_handler2来处理,下次就会调用new_handler2来处理。

 

处理方式3:卸载new_handler

std::set_new_handler(NULL)来卸载new_handler,则operator new在内存分配失败时不会调用错误处理函数new_handler而直接抛出异std::bad_alloc并且Abort掉程序。

 

处理方式4:抛出std::bad_alloc或者派生自std::bad_alloc的异常。

这样异常不会被operator new捕捉,因此会被传播到内存索求处。

处理方式5:调用abort或exit

 

下面这五种处理方式中的几种方式,进行编码实现。

处理方式2:安装另一个new_handler

如果new_handler1无法处理时,就在new_handler1内部调用set_new_handler设置new_handler2来处理,下次就会调用new_handler2来处理。

#include <stdlib.h>	//for abort()
#include <iostream>
void handle_outOfMem2()
{
std::cerr<<__FUNCTION__<<":operator new unable to satisfy request for memory, try allocate memory again.\n";
}
void handle_outOfMem()
{
std::cerr<<__FUNCTION__<<":operator new unable to satisfy request for memory, try allocate memory again.\n";
std::set_new_handler(handle_outOfMem2);
}
int main()
{
std::set_new_handler(handle_outOfMem );
int *buf = new int[1000000000L];
delete []buf;
return 0;
}


测试结果如下所示:



处理方式3:卸载new_handler

std::set_new_handler(NULL)来卸载new_handler,则operator new在内存分配失败时不会调用错误处理函数new_handler。

#include <stdlib.h>	//for abort()
#include <iostream>
void handle_outOfMem()
{
std::cerr<<__FUNCTION__<<":operator new unable to satisfy request for memory, try allocate memory again.\n";
std::set_new_handler(NULL);
}
int main()
{
std::set_new_handler(handle_outOfMem );
int *buf = new int[1000000000L];
delete []buf;
return 0;
}


测试结果如下所示:



处理方式5:调用abort或exit

#include <stdlib.h>	//for abort()
#include <iostream>
void handle_outOfMem()
{
std::cerr<<"operator new allocate memory failed, try again.\n";
abort();
}
int main()
{
std::set_new_handler(handle_outOfMem );
int* buf = new int[1000000000000000L];
delete []buf;
return 0;
}
测试结果如下所示:



在C++开发的工程项目中,一般可能需要对具体class注册自定义的new_handler,具体可以参考《Effective C++ 改善程序与设计的55个具体做法》。

(完)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: