条款 7:预先准备好内存不够的情况 set_new_handler

时间:2023-01-16 19:33:40

         operator new 在无法完成内存分配请求时会抛出异常(以前的做法一般是返回 0,一些旧一点的编译器还这么做)。

         用一个很简单的出错处理方法,可以这么做:当内存分配请求不能满足时,调用你预先指定的一个出错处理函数。这个方法基于
一个常规,即当 operator new 不能满足请求时,会在抛出异常之前调用客户指定的一个出错处理函数——一般称为 new-handler 函数。(operator new 实际工作起来要复杂一些,详见条款 8)

        指定出错处理函数时要用到 set_new_handler 函数,它在头文件<new>里大致是象下面这样定义的:  

typedef void (*new_handler)();
new_handler set_new_handler(new_handler p) throw();
        可以看到,new_handler 是一个自定义的函数指针类型,它指向一个没有输入参数也没有返回值的函数。 set_new_handler 则是一个输入并返回new_handler 类型的函数。

        set_new_handler 的输入参数是 operator new 分配内存失败时要调用的出错处理函数的指针,返回值是 set_new_handler 没调用之前就已经在起作用的旧的出错处理函数的指针。

       可以象下面这样使用 set_new_handler:

// function to call if operator new can't allocate enough memory
void noMoreMemory()
{
cerr << "Unable to satisfy request for memory\n";
abort();
}
int main()
{
set_new_handler(noMoreMemory);
int *pBigDataArray = new int[100000000];
...
}
        假如 operator new 不能为 100,000,000 个整数分配空间,noMoreMemory将会被调用,程序发出一条出错信息后终止。这就比简单地让系统内核产生错误信息来结束程序要好。

        operator new 不能满足内存分配请求时,new-handler 函数不只调用一次,而是不断重复,直至找到足够的内存。

        一个设计得好的 new-handler 函数必须实现下面功能中的一种。

       产生更多的可用内存。这将使 operator new 下一次分配内存的尝试有可能获得成功。实施这一策略的一个方法是:在程序启动时分配一个大的内存块,然后在第一次调用 new-handler 时释放。释放时伴随着一些对用户的警告信息,如内存数量太少,下次请求可能会失败,除非又有更多的可用空间。

       安装另一个不同的 new-handler 函数。如果当前的 new-handler 函数不能产生更多的可用内存,可能它会知道另一个 new-handler 函数可以提供更多的资源。 这样的话, 当前的 new-handler 可以安装另一个 new-handler 来取代它(通过调用 set_new_handler)。下一次 operator new 调用 new-handler 时,会使用最近安装的那个。