分享

处理new分配失败

 terryecnu 2014-06-16
分类: c++ 2011-11-21 21:07 909人阅读 评论(0) 收藏 举报

1993年前,c++一直要求在内存分配失败时operator new要返回0,现在则是要求operator new抛出std::bad_alloc异常。很多c++程序是在编译器开始支持新规范前写的。c++标准委员会不想放弃那些已有的遵循返回0规范的代码,所以他们提供了另外形式的operator new(以及operator new[])以继续提供返回0功能。这些形式被称为“无抛出”,因为他们没用过一个throw,而是在使用new的入口点采用了nothrow对象:

  1. class widget { ... };  
  2.   
  3. widget* pw1 = new widget;// if allocated failed throw std::bad_alloc  
  4.   
  5. if (pw1 == 0) ...   // must be failed  
  6.   
  7. widget* pw2 = new (nothrow)widget;  // if allocated failed return 0(NULL)  
  8.       
  9. if (pw2 == 0) ...   // maybe successful   

operator new默认情况下如果不能满足内存分配请求时会抛出的异常类型std::bad_alloc。因此,如果你不愿意看到诸如:widget* pw2 = new (nothrow) widget; 这样带着nothrow的operator new,最简单的方法是使用set_new_handler自定义newhandler函数。最简单的例子如下:

  1. // main.cpp (vc9.0)  
  2.   
  3. #include "stdafx.h"  
  4. #include<new>  
  5. #include<iostream>  
  6. #include<stdlib.h>  
  7. using namespace std;  
  8.   
  9. void __cdecl newhandlerfunc()  
  10. {  
  11.     cerr << "Allocate failed." << endl;  
  12.     abort();  
  13. }  
  14.   
  15. int main()   
  16. {  
  17.     set_new_handler (newhandlerfunc);  
  18.     while (1)   
  19.     {  
  20.         int* p = new int[500000000];    // based on own machine's memory size  
  21.         cout << "Allocating 500000000 int." << endl;  
  22.     }  
  23. }  

newhandlerfunc函数中没有参数也没有返回值,可提供的信息有限,这样的全局通用函数在c++项目中所能起的作用不大。所以,鉴于c++本身的面向对象的设计,我们考虑每个类有自己的newhandler,与全局的newhandler共存。比较简单的例子如下:

  1. // main.cpp (vc9.0)  
  2.   
  3. #include "stdafx.h"  
  4. #include<new>  
  5. #include<iostream>  
  6. #include<stdlib.h>  
  7. using namespace std;  
  8.   
  9. void __cdecl newhandlerfunc()  
  10. {  
  11.     cerr << "Allocate failed." << endl;  
  12.     abort();  
  13. }  
  14.   
  15. void __cdecl xnewhandlerfunc()  
  16. {  
  17.     cerr << "Allocate x object failed" << endl;  
  18.     abort();  
  19. }  
  20.   
  21. class x {  
  22. public:  
  23.     x()  
  24.     {  
  25.         while (1)   
  26.         {  
  27.             int* p = new int[500000000];  
  28.             cout << "Allocating 500000000 int." << endl;  
  29.         }  
  30.     }  
  31.   
  32.     static new_handler set_new_handler(new_handler p)  
  33.     {  
  34.         new_handler oldhandler = currenthandler;  
  35.         currenthandler = p;  
  36.         return oldhandler;  
  37.     }  
  38.   
  39.     static void * operator new(size_t size)  
  40.     {  
  41.         // setup x's new_handler, now it replaces global handler  
  42.         new_handler globalhandler = set_new_handler(currenthandler);   
  43.   
  44.         void *memory;  
  45.         try   
  46.         {     
  47.             memory = ::operator new(size); // try to allocate memory  
  48.         }  
  49.         catch (std::bad_alloc&) // handled by x's new_handler  
  50.         {     
  51.             set_new_handler(globalhandler); // recover old new_handler       
  52.             throw;  // rethrow exception  
  53.         }  
  54.   
  55.         // allocate normally  
  56.         std::set_new_handler(globalhandler);    // recover old new_handler   
  57.         return memory;  
  58.     }  
  59.   
  60. private:  
  61.     static new_handler currenthandler;  
  62. };  
  63.   
  64. new_handler x::currenthandler = NULL;  
  65.   
  66. int main()   
  67. {  
  68.     //set_new_handler(newhandlerfunc);  
  69.     //while (1)   
  70.     //{  
  71.     //  int* p = new int[500000000];  
  72.     //  cout << "Allocating 500000000 int." << endl;  
  73.     //}  
  74.     x::set_new_handler(xnewhandlerfunc);  
  75.     x* p = new x;  
  76.   
  77.     return 0;  
  78. }  

如果每个类都这样地写一遍,感觉有些代码重复,所以可能想到会写一个基类,让所有的子类可以继承set_new_handler和operator new功能,但要使每个子类有不同的currenthandler数据成员,一个比较简单的方法就是设计一个模板。
例子如下:

  1. // SetNewHandler.h (vc9.0)  
  2.   
  3. #include<new>  
  4. #include<iostream>  
  5. #include<stdlib.h>  
  6. using namespace std;  
  7.   
  8. template<class t>   
  9. class newhandlersupport {     
  10. public:  
  11.     static new_handler set_new_handler(new_handler p);  
  12.     static void * operator new(size_t size);  
  13.   
  14. private:  
  15.     static new_handler currenthandler;  
  16. };  
  17.   
  18. template<class t>  
  19. new_handler newhandlersupport<t>::set_new_handler(new_handler p)  
  20. {  
  21.     new_handler oldhandler = currenthandler;  
  22.     currenthandler = p;  
  23.     return oldhandler;  
  24. }  
  25.   
  26. template<class t>  
  27. void * newhandlersupport<t>::operator new(size_t size)  
  28. {  
  29.     new_handler globalhandler = set_new_handler(currenthandler);  
  30.     void *memory;  
  31.     try   
  32.     {  
  33.         memory = ::operator new(size);  
  34.     }  
  35.     catch (std::bad_alloc&)   
  36.     {  
  37.         set_new_handler(globalhandler);  
  38.         throw;  
  39.     }  
  40.   
  41.     std::set_new_handler(globalhandler);  
  42.     return memory;  
  43. }  
  44.   
  45. template<class t>  
  46. new_handler newhandlersupport<t>::currenthandler = NULL;  

 

  1. // main.cpp (vc9.0)  
  2.   
  3. #include "stdafx.h"  
  4. #include "SetNewHandler.h"  
  5. #include<new>  
  6. #include<iostream>  
  7. #include<stdlib.h>  
  8. using namespace std;  
  9.   
  10. void __cdecl newhandlerfunc()  
  11. {  
  12.     cerr << "Allocate failed." << endl;  
  13.     abort();  
  14. }  
  15.   
  16. void __cdecl xnewhandlerfunc()  
  17. {  
  18.     cerr << "Allocate x object failed" << endl;  
  19.     abort();  
  20. }  
  21.   
  22. void __cdecl ynewhandlerfunc()  
  23. {  
  24.     cerr << "Allocate y object failed" << endl;  
  25.     abort();  
  26. }  
  27.   
  28. class x {  
  29. public:  
  30.     x()  
  31.     {  
  32.         while (1)   
  33.         {  
  34.             int* p = new int[500000000];  
  35.             cout << "Allocating 500000000 int." << endl;  
  36.         }  
  37.     }  
  38.   
  39.     static new_handler set_new_handler(new_handler p)  
  40.     {  
  41.         new_handler oldhandler = currenthandler;  
  42.         currenthandler = p;  
  43.         return oldhandler;  
  44.     }  
  45.   
  46.     static void * operator new(size_t size)  
  47.     {  
  48.         // setup x's new_handler, now it replaces global handler  
  49.         new_handler globalhandler = set_new_handler(currenthandler);  
  50.   
  51.         void *memory;  
  52.         try   
  53.         {     
  54.             memory = ::operator new(size); // try to allocate memory  
  55.         }  
  56.         catch (std::bad_alloc&) // handled by x's new_handler  
  57.         {     
  58.             set_new_handler(globalhandler); // recover old new_handler       
  59.             throw;  // rethrow exception  
  60.         }  
  61.   
  62.         // allocate normally  
  63.         std::set_new_handler(globalhandler);    // recover old new_handler   
  64.         return memory;  
  65.     }  
  66.   
  67. private:  
  68.     static new_handler currenthandler;  
  69. };  
  70.   
  71. new_handler x::currenthandler = NULL;  
  72.   
  73. class y: public newhandlersupport<y>   
  74. {  
  75. public:  
  76.     y()  
  77.     {  
  78.         while (1)   
  79.         {  
  80.             int* p = new int[500000000];  
  81.             cout << "Allocating 500000000 int." << endl;  
  82.         }  
  83.     }  
  84. };        
  85.   
  86. int main()   
  87. {  
  88.     //set_new_handler(newhandlerfunc);  
  89.     //while (1)   
  90.     //{  
  91.     //  int* p = new int[500000000];  
  92.     //  cout << "Allocating 500000000 int." << endl;  
  93.     //}  
  94.   
  95.     //x::set_new_handler(xnewhandlerfunc);  
  96.     //x* p = new x;  
  97.   
  98.     y::set_new_handler(ynewhandlerfunc);  
  99.     y* p = new y;  
  100.   
  101.     return 0;  
  102. }  

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多