effective C++ series(one)

本文介绍如何在C++中处理内存分配失败的情况,包括使用set_new_handler设置内存分配失败的处理函数,以及通过自定义new操作符实现特定类的内存管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. /*                         
  2.                                        effective C++
  3. Shifting from C to C++  
  4. Item 1:    Prefer const and inline to #define.  
  5. Item 2:    Prefer <iostream> to <stdio.h>.  
  6. Item 3:    Prefer new and delete to malloc and free.  
  7. Item 4:    Prefer C++-style comments.  
  8. Memory Management  
  9.    
  10. Item 5:    Use the same form in corresponding uses of new and delete.  
  11. Item 6:    Use delete on pointer members in destructors.  
  12. */
  13. Item 7:  Be prepared for out-of-memory conditions. 
  14. To specify the out-of-memory-handling function, clients call set_new_handler, which is specified in the header <new> more or less like this
  15. typedef void (*new_handler)();
  16. new_handler set_new_handler(new_handler p) throw();
  17. As you can see, new_handler is a typedef for a pointer to a function that takes and returns nothing, and set_new_handler is a function that takes and returns a new_handler. 
  18. set_new_handler's parameter is a pointer to the function operator new should call if it can't allocate the requested memory. The return value of set_new_handler is a pointer to the function in effect for that purpose before set_new_handler was called. 
  19. You use set_new_handler like this
  20. // function to call if operator new can't allocate enough memory
  21. void noMoreMemory()
  22. {
  23.   cerr << "Unable to satisfy request for memory/n";
  24.   abort();
  25. }
  26. int main()
  27. {
  28.   set_new_handler(noMoreMemory);
  29.   int *pBigDataArray = new int[100000000];
  30.   ...
  31. }
  32. Sometimes you'd like to handle memory allocation failures in different ways, depending on the class of the object being allocated: 
  33. class X {
  34. public:
  35.   static void outOfMemory();
  36.   ...
  37. };
  38. class Y {
  39. public:
  40.   static void outOfMemory();
  41.   ...
  42. };
  43. X* p1 = new X;      // if allocation is unsuccessful,call X::outOfMemory
  44. Y* p2 = new Y;      // if allocation is unsuccessful, call Y::outOfMemory
  45. Consider a class X for which you want to handle memory allocation failures. You'll have to keep track of the function to call when operator new can't allocate enough memory for an object of type X, so you'll declare a static member of type new_handler to point to the new-handler function for the class. Your class X will look something like this
  46. class X {
  47. public:
  48.   static new_handler set_new_handler(new_handler p);
  49.   static void * operator new(size_t size);
  50. private:
  51.   static new_handler currentHandler;
  52. };
  53. Static class members must be defined outside the class definition. Because you'll want to use the default initialization of static objects to 0, you'll define X::currentHandler without initializing it: 
  54. new_handler X::currentHandler;      // sets currentHandler to 0 (i.e., null) by default
  55. The set_new_handler function in class X will save whatever pointer is passed to it. It will return whatever pointer had been saved prior to the call. This is exactly what the standard version of set_new_handler does: 
  56. new_handler X::set_new_handler(new_handler p)
  57. {
  58.   new_handler oldHandler = currentHandler;
  59.   currentHandler = p;
  60.   return oldHandler;
  61. }
  62. Here's how you say all that in C++: 
  63. void * X::operator new(size_t size)
  64. {
  65.   new_handler globalHandler =                // install X's
  66.     std::set_new_handler(currentHandler);    // handler
  67.   void *memory;
  68.   try {                                      // attempt
  69.     memory = ::operator new(size);           // allocation
  70.   }
  71.   catch (std::bad_alloc&) {                  // restore
  72.     std::set_new_handler(globalHandler);     // handler;
  73.     throw;                                   // propagate
  74.   }                                          // exception
  75.   std::set_new_handler(globalHandler);       // restore
  76.                                              // handler
  77.   return memory;
  78. }
  79. Clients of class X use its new-handling capabilities like this
  80. void noMoreMemory();                           // decl. of function to
  81.                                                // call if memory allocation for X objects fails
  82. X::set_new_handler(noMoreMemory);
  83.                                                // set noMoreMemory as X's new-handling function
  84. X *px1 = new X;                                // if memory allocation fails, call noMoreMemory
  85. string *ps = new string;  // if memory allocation fails, call the global new-handling function (if there is one)
  86. X::set_new_handler(0); // set the X-specific new-handling function to nothing (i.e., null)
  87. X *px2 = new X;     // if memory allocation fails, throw an exception immediately. 
  88.                     //(There is no new-handling function for class X.)
  89. template<class T>               // "mixin-style" base class
  90. class NewHandlerSupport {           // for class-specific
  91. public:                     // set_new_handler support
  92.   static new_handler set_new_handler(new_handler p);
  93.   static void * operator new(size_t size);
  94. private:
  95.   static new_handler currentHandler;
  96. };
  97. template<class T>
  98. new_handler NewHandlerSupport<T>::set_new_handler(new_handler p)
  99. {
  100.   new_handler oldHandler = currentHandler;
  101.   currentHandler = p;
  102.   return oldHandler;
  103. }
  104. template<class T>
  105. void * NewHandlerSupport<T>::operator new(size_t size)
  106. {
  107.   new_handler globalHandler =
  108.     std::set_new_handler(currentHandler);
  109.   void *memory;
  110.   try {
  111.     memory = ::operator new(size);
  112.   }
  113.   catch (std::bad_alloc&) {
  114.     std::set_new_handler(globalHandler);
  115.     throw;
  116.   }
  117.   std::set_new_handler(globalHandler);
  118.   return memory;
  119. }
  120. // this sets each currentHandler to 0
  121. template<class T>
  122. new_handler NewHandlerSupport<T>::currentHandler;
  123. With this class template, adding set_new_handler support to class X is easy: X just inherits from newHandlerSupport<X>: 
  124. // note inheritance from mixin base class template. (See
  125. // my article on counting objects for information on why
  126. // private inheritance might be preferable here.)
  127. class X: public NewHandlerSupport<X> {
  128.   ...                 // as before, but no declarations for
  129. };                    // set_new_handler or operator new
  130. Clients of X remain oblivious to all the behind-the-scenes action; their old code continues to work. This is good, because one thing you can usually rely on your clients being is oblivious. 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值