C++ new_handler空间分配失败处理
动态分配空间、内存动态分配与回收对于任何一个程序员来说都尤为重要,特别是嵌入式C/C++程序员更为如此,malloc, remalloc, new等等,很有可能就申请空间失败,对申请失败的异常处理更是比较棘手。在C++中提倡使用new来代替malloc,因为new比malloc更加安全,更加效率。
很多程序员,包括我自己都喜欢性的使用这种C/C++代码来申请空间。
#include <iostream>
#include <windows.h>
using namespace std;
typedef int Type;
typedef struct _Node
{
Type data;
struct _Node *next;
}Node;
int main(void)
{
Node *pNode = (Node *)(malloc(sizeof(Node)));
if (!pNode)
{
abort();
}
return 0;
}
C++中,这里有问题吗?C程序员来说一般都会写类似的代码。
C++中,很多错误都会以异常的方式抛出,而且对于一个稍大的项目来说异常处理通常会设计专门的异常类去处理。
在《Effective C++》中则提到了一个比较智能的使用异常的方式去处理动态分配空间失败:
//这里先提到,详细的解释和代码在后面
new_handler;
new_handler set_new_handler(new_handler p);
他们被定义在
#include <new>
using namespace std;
new_handler和set_new_handler的申明如下:
//new_handler
typedef void (×new_handler)();
//set_new_handler
new_handler set_new_handler(new_handler p);
new_handler是一个参数为空的函数指针。
set_new_handler就是设置异常处理函数的入口,有程序员自己定义然后传入。
当空间分配失败之后,就会调用new_handler异常处理函数,然后才会抛出异常。也就是说异常的抛出是在调用new_handler之后。
对于一个动态内存分配失败的异常处理函数应该至少具有以下几个特点:
1.确保内存分配成功。
所谓确保内存分配成功,也就是说当new的时候不会失败。这是一个策略问题。我们可以在调用new之前,就申请一块较大的空间,当new空间的时候,就是放一点
2.设置不同的new_handler。
对于这一点,我们可以通过改变new_handler的参数以及申请空间的数量来做到。以确保下次申请空间成功。
3. 解除new_handler。
即传入NULL指针。
4.异常抛出。
那么。实际上,以上4点,set_new_handler已经可以做到了。
#include <iostream>
#include <new> //new_handler,set_new_handler
#include <windows.h>
using namespace std;
void NoMemory()
{
cout << "No adequate memory left" << endl;
abort();
}
int main(void)
{
set_new_handler(NoMemory);
//这里实际很难碰到申请失败的情况
BYTE *pData = new BYTE[0x5fffffff];
return 0;
}
实际上,如果new_handler中没有abort的话,new_handler会被循环的调用下去,直到申请空间成功为止。