Valid C ++ clause 49, valid clause 49
Understand new-handler Behaviors
The technology described in the terms of this section is that before operator new throws an exception, an error handler specified by the customer is called: new-handler. How to customize and use this memory exception handler when memory allocation fails. The key statement isset_new_handler
. The author emphasizes how to allocate class memory to implement different memory allocation error handling functions.
Let's first give an example in the book to figure out how to use the new-handler technology.
The following code:
Void outOfMem () {std: cerr <"Unable to satisfy request for memoryn"; std: abort (); // force terminate the process} int main () {std: set_new_handler (outOfMem); int * pBigDataArray = new int [random distinct L]; return 0 ;}
The above code is called becauseset_new_handler(outOfMem);
If the memory allocation fails, it will go to the outOfMen function for further execution. In this way, we will come up with the idea of using different functions to solve the memory allocation problem of different classes defined by ourselves. For example, Class A has A user-defined memory processing function for Class A and Class B has A user-defined memory processing function for Class B. to implement this function, the author proposes the following implementation methods.
However, the memory processing functions we define must have the following features:
1. Make more memory available. In this way, the next memory allocation operation in operator new may be successful. One way is that the program allocates a large block of memory at the beginning and releases it when new-handler is called for the first time.
2. install another new-handler. When the current new-handler cannot obtain more memory, it may be available to the new-handler.
3. Remove new-handler. Pass the null pointer to set_new_handler. Once no new-handler is installed, operator new throws an exception when the memory allocation is unsuccessful.
4. Throw an exception of bad_alloc (or derived from bad_alloc. Such exceptions will not be caught by operator new, so they will not be propagated to the memory claim.
5. No response is returned. Usually abort or exit.
Class NewHandlerHolder {public: explicit NewHandlerHolder (std: new_handler nh): handlere (nh ){}~ NewHandlerHolder () {std: set_new_handler (handler);} private: std: new_handler handler; NewHandlerHolder & (const NewHandlerHolder &); // prevent copying NewHandlerHolder & operator-(const NewHandlerHolder &);}; class Widget {public: static std: new_handler set_new_handler (std: new_handler p) throw (); static void * operator new (std: size_t size) throw (std: bad_alloc); private: static std: new_handler currentHandler;}; std: new_handler Widget :: currentHandler = 0; std: new_handler Widget: handler (std: new_handler p) throw () {std: new_handler oldHandler = currentHandler; currentHandler = p; reutrn oldHandler ;} void * Widget: operator new (std: size_t size) throw (std: bad_alloc) {NewHandlerHolder h (std: set_new_handler (currentHandler )); // install the new-handler return: operator new (size);} void outOfMem (); Widget: set_new_handler (outOfMem ); // set outOfmem to the new-handling function Widget * pw1 = new Widget of the Widget; // if the memory allocation fails, call outOfMEM std: string * ps = new std: string; // if the memory allocation fails, call global new-handling (if any) Widget: set_new_handler (0); // set the Widget's exclusive new-handling to null Widget * pw2 = new Widget; // if the memory allocation fails, an exception is thrown immediately.
Let me explain, the above program, for definitionclass NewHandlerHolder
To save the memory processing function before replacement, let's track the execution process of the above Code. First, declareoutOfMem()
And then passWidget::set_new_handler(outOfMem)
Statement settingsWidget
Internalstatic std::new_handler currentHandler
Variable. Then, callnew Widget
, We enterWidget::operator new(std::size_t size) throw(std::bad_alloc)
Function body,NewHandlerHolder h(std::set_new_handler(currentHandler));
Statement:NewHandlerHolder
When the object is replaced, the former memory handler is saved instd::new_handler handler
In the variable, 2. Set a new new_handler function for the class Widget. Run::operator new(size)
Memory Allocation. If an error occurs in memory allocation, the new memory handler is called. When exiting the function body, becauseNewHandlerHolder
To restore the memory processing function, without affecting the execution of other memory allocation exceptions in the future.
The above versions provide the required functions.
However, the author proposes another method to implement the template:
Class NewHandlerHolder {public: explicit NewHandlerHolder (std: new_handler nh): handlere (nh ){}~ NewHandlerHolder () {std: set_new_handler (handler);} private: std: new_handler handler; NewHandlerHolder & (const NewHandlerHolder &); // prevent copying NewHandlerHolder & operator-(const NewHandlerHolder &) ;}; template <typename T> class NewHandlerSupport {public: static std: new_handler set_new_handler (std: new_handler p) throw (); static void * operator new (std: size_t size) throw (std: bad_alloc );...... Private: static std: new_handler currentHandler;}; template <typename T> std: new_handler NewHandlerSupport <T >:: set_new_handler (std: new_handler p) throw () {std:: new_handler oldHandler = currentHandler; currentHandler = p; return oldHandler;} template <typename T> void * NewHandlerSupport <T >:: operator new (std: size_t size) throw (std:: bad_alloc) {NewHandlerHolder h (std: set_new_handler (currentHandler); return: operator new (size); template <typename T> std: new_handler NewHandlerSupport <T> :: currentHandler = 0; class Widget: public NewHandlerSupport <Widget> {};
This implementation method is awkward for me, but it reflects the potential programming value of the template. When we call the statementclass Widget:public NewHandlerSupport<Widget>
We instantiateNewHandlerSupport<Widget>
Class, our classWidget
The widget class inherits the NewHandlerSupport function. The actual program execution process is the same as the first method, the only difference is that the class widgets do not need to redefine static functions related to memory processing.