《STL源码剖析》中关于set_new_handler的理解

问题背景

  在阅读侯杰的《STL源码剖析》的时候,在书中的p45页遇到一段代码,书中并没有给予详细的解释,查阅资料发现网上的解释并不是那么尽如人意,在查阅了《effective C++》这本书之后,总结写出了这篇博客。书中的“问题代码”:

template<class T>
inline T* _allocate(ptrdiff_t size,T*){
    set_new_handler(0);//书中没有解释此处代码的含义
    T *tmp=(T*)::operator new((size_t)(size*sizeof(T));
    if(tmp==0){
    cerr<<"out of memory"<exit(1);
    }
    return tmp;
}   

追跟溯源set_new_handler的由来

  我们知道当operator new无法满足某一个内存分配的需求的时候,它会抛出一个异常,在这之前,它会先调用一个客户制定的错误处理函数new_handler。为了指定这个来处理内存不足的函数,使用者需要调用标准库程序函数set_new_handler:

namespace std{
    typedef void (*new_handler){ };//一个函数指针
    new_handler set_new_handler(new_handler p) throw();
};

  从源代码中,我们可以看出set_new_handler实际上就是一个形参和返回值类型都是new_handler的函数。

如何使用set_new_handler

  前面我们提到,当operator new无法分配足够的内存时,set_new_handler函数会被调用。那么这一过程具体是怎么发生的呢?我们还是通过一个例子来理解:

void outOfMem(){
    std::cerr<<"Unable to statisfy request for memory\n";
    std::abort();
}
int main()
{
    set_new_handler(outOfMem);
    int *pBigDataArray=new int[100000000L];
    ...
}

  在本程序中,如果不能为operator new分配所需要的100000000个整数的空间,outOfMem就会被调用,于是程序终止(abort)。如果一直不能满足的话,outOfMem也就是之前所说的new_handler函数会不断被调用。

怎样设计一个性能优良的new_handler

  既然我们已经知道了如何使用set_new_handler,那么我们接下来来看一下一个如何设计一个良好的new_handler需要做哪些事情吧:

  1. 让更多的内存被使用。这样做的目的很简单,就是为了内存能够尽可能被operator new进行分配。实现此要求的做法是,当new_handler被调用的时候,将之前分配的内存释放给程序,以便能够继续使用。
  2. 安装新的new_handler。如果当前的new_handler无法取得更多的内存,那么这个new_handler应该能够安装新的new_handler以便能够获得更多的内存空间。
  3. 卸载new_handler,也就是将null指针传给set_new_handler。这样的话,一旦没有分配成功,就会抛出异常。
  4. 抛出bad_alloc的异常。这样的异常不会被operator_new捕捉,因此会被传播到内存索求处。
  5. 不返回。通常会调用abort或者exit。

这下你对set_new_handler的使用和发挥作用的机制更了解了吧。

你可能感兴趣的:(STL源码剖析)