就像可以用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是声明于
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 //for abort()
#include
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 //for abort()
#include
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 //for abort()
#include
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 //for abort()
#include
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个具体做法》。
(完)