首先让我们了解下new-handler的行为:在opeartor new抛出异常以反应一个未获满足的内存需求之前,它会先调用一个客户指定的错误处理函数,一个所谓的new-handler。(这其实并非全部事实,operator new真正做的事情稍微更复杂些,详见条款51。)为了指定这个“用以处理内存不足的函数”,客户必须调用set_new_handler,那是声明<new>的一个标准程序库函数:
namespace std
{
typedef void(*new_handler)();
new_handler set_new_handler(new_handler p)throw();
}
如你所见,new_handler是个typdef,定义出一个函数指针类型,所指向的函数是没有参数也不返回任何东西。set_new_handler则是“获得一个new_handler并返回一个new_handler”的函数。set_new_handler的参数是一个指针,指向operator new 无法分配足够内存时该被调用的函数,其返回值也是个指针,指向调用set_new_handler时要被替换的那个new-handler函数。
当operator new无法满足内存申请时,它会不断调用new-handler函数,直到找到足够内存。引起反复调用的代码显示于条款51,这里的高级描述已足够获得一个结论,那就是一个设计良好的new-handler函数必须做的事情:
1.让更多内存可被调用。 这便造成operator new 内的下一次内存分配动作可能成功。实现此策略的一个做法是,程序一开始执行就分配一大块内存,而后当new-handler第一次被调用,将它们释还给程序使用。
2.安装另一个new-handler。如果目前这个new-handler无法取得更多可用内存,或许它知道另外哪个new-handler有此能力。果真如此,目前这个new-handler就可以安装另外那个new-handler以替换自己(只要调用set_new_handler)。下次当operator new调用new-handler,调用的将是最新安装的那个
3.卸载new-handler。也就是将null指针传给set_new_handler。一旦没有安装任何new-handler,operator new 会在内存分配不成功时抛出异常。
4.抛出bad_alloc(或派生字bad_alloc)的异常。这样的异常不会被operator new 捕捉,因此会被传播给内存索求处。
5.不返回。通常调用abort或exit.
这些选择让你在实现new-handler函数时拥有很大弹性。
好,知道这些后我们就开始简单地实现类的特定的set_new_handler,operator new ,operator delete
见代码:#include <iostream> using namespace std; class NewHandlerHolder //用于恢复原来的new-handler,思想采用RAII机制 { public: explicit NewHandlerHolder(new_handler h); ~NewHandlerHolder(); private: new_handler m_handler; NewHandlerHolder(const NewHandlerHolder& rhs); new_handler& operator=(const NewHandlerHolder& rhs); }; NewHandlerHolder::NewHandlerHolder(new_handler h) { m_handler=h; } NewHandlerHolder::~NewHandlerHolder() { set_new_handler(m_handler); } //建立一个"mixin"风格的base class,这种base class用来允许derrived classes继承特定的功能(特定的set_new_handler,operator new ,operator delete) template<class T> class NewHandlerSupport { public: static new_handler set_new_handler(new_handler p) throw(); static void* operator new(size_t size) throw(bad_alloc); static void operator delete (void* pMem,size_t size); protected: static new_handler m_CurrentHandler; }; template<class T> new_handler NewHandlerSupport<T>::m_CurrentHandler=0; template<class T> new_handler NewHandlerSupport<T>::set_new_handler(new_handler p) throw() { new_handler oldHandler=m_CurrentHandler; m_CurrentHandler=p; return oldHandler; } template<class T> void* NewHandlerSupport<T>::operator new(size_t size) throw(bad_alloc) { NewHandlerHolder(::set_new_handler(m_CurrentHandler)); return ::operator new(size); } template<class T> void NewHandlerSupport<T>::operator delete(void* pMem,size_t size) { return ::operator delete(pMem); } class widget:public NewHandlerSupport<widget> { public: protected: private: }; void OutMemory() { cerr<<"unable to satisfy request for memory"<<endl; abort(); } int main() { widget::set_new_handler(OutMemory); widget* p=new widget; delete p; p=NULL; return 0; }