1. new_handler function: the function called when operator new or operator new [] memory allocation fails.
Set_new_handler function: This function is used to allocate more memory. If it succeeds, it will return. Otherwise, it will throw a bad_alloc exception (or its derived class Object) or call the abort () or exit () of cstdlib () the function is forced to exit.
References: http://www.cplusplus.com/reference/std/new/set_new_handler/
Http://www.cplusplus.com/reference/std/new/new_handler/
2. when operator new fails to allocate memory (insufficient), it first calls the New-handler function specified by the customer and throws an exception (the old behavior is to return a null pointer ). The customer uses set_new_handler to set this behavior. It is a standard library function declared in <New>:
Namespace STD {typedef void (* new_handler) (); // pointer to the Function
New_handler set_new_handler (new_handler p) Throw (); // gets the function pointer that should be called when the memory allocation fails, and returns the function that is being executed before the call (but will be replaced immediately) new-handler function pointer
} When operator new cannot meet the memory application, it will call the new-handler function until the memory is sufficient.
Note: Operator new functions are different from new functions. The former is the implementation in the standard library. It is a function, but not a overload, while the latter is an expression.
3. A well-designed new-handler function must do the following:
- So that more memory can be used. One way is that the program allocates a large amount of memory at the beginning. When new-handler is called, the memory space is returned to the program.
- Install another new-handler. If the current new-handler function cannot apply for sufficient memory, you can use set_new_handler to replace it with another suitable version.
- Remove the New-handler and pass the NULL pointer to set_new_handler. Once no new-handler is installed, operator new will throw an exception when the allocation fails.
- Throw an exception of bad_alloc (or its derived class object. Such exceptions will not be caught by operator new, so they will be propagated to the memory application.
- If no value is returned, abort () or exit () is usually called ().
4. to support the class-specific new-handler, you can declare the required new_handler function in the class and provide the class-specific set_new_handler (specify new-handler) and operator new (ensure that the global new-handler is replaced with the class-exclusive New-handler in the process of allocating Class Object Memory. The specific process is as follows:
(1) declare a static member function of the new_handler type to point to the new-handler of the class. For example:
1: class Widget{
2:
3: public:
4:
5: static std::new_handler set_new_handler(std::new_handler p) throw();
6:
7: static void* operator new(std::size_t size) throw(std::bad_alloc);
8:
9: private:
10:
11: static std::new_handler currentHandler;
12:
13: };
Note that the static member must be defined outside the class (unless it is const and INT type), so you need to write it like this:
std::new_handler Widget::currentHandler = 0;
(2) The set_new_handler function stores the obtained pointer and returns the pointer stored before the call (same as the standard set_new_handler:
std::new_handler Widget::set_new_handler(std::new_handler p) thorw(){std::new_handler oldHandler = currentHandler;currentHandler = preturn oldHandler;}
(3) Enable operator new of this class to do the following:
- Call the standard set_new_handler to inform the error handler of this class. This will install the new-handler of this class as the Global New-handler.
- Call the global operator new to execute the actual memory allocation. If the allocation fails, the global operator new will call the new-handler of the class, because the function has just been installed as a global new-handler. If the global new-handler cannot allocate enough memory, the bad_alloc exception will be thrown. In this case, operator new of this class must restore the original Global New-handler and then spread the exception. To ensure that the original New-handler can always be reinstalled, this class regards the global new-handler as a "resource" and uses the resource management object to prevent resource leakage.
- If the global operator new can allocate enough memory, a pointer is returned pointing to the allocated address. The destructor of this class manages global new-handler, and it automatically restores the Global New-handler before the class operator new is called.
5. instance: Starting from the resource processing class, there are only basic raiI operations. A resource is obtained during the construction process and returned during the analysis process:
Class newhandlerholder {public: explicit newhandlerholder (STD: new_handler NH): handler (NH) {}// get the current new-handler ~ Newhandlerholder () {STD: set_new_handler (handler);} // release new-handlerprivate: STD: new_handler handler; // save New-handlernewhanlderholder (const newhandlerholder &); // block replication behavior newhandlerholder & operator = (const newhandlerholder &);};
Suppose there is a class widget that implements the operator new method:
Void * Widget: Operator new (STD: size_t size) Throw (STD: bad_alloc) {newhandlerholder H (STD: set_newhandler (currenthandler )); // install the new-handlerreturn: Operator new (size) of the widget; // allocate memory or throw an exception to restore global new-handler}
The customer of the widget should adopt the following method: New-handler:
Void outofmem (); // declare the processing function widget when memory allocation fails: set_new_handler (outofmem ); // set the above function to the new-handler function widget * pw1 = new widget of the widget; // if the memory allocation fails, call outofmem () STD :: string * PS = new STD: string; // If memory allocation fails, call the Global New-handler function (if any) Widget: set_new_handler (0 ); // set the new-handler of the widget to be empty and the widget * pw2 = new widget of the exclusive version is lost. // if the memory allocation fails, an exception is thrown.
The preceding method can be abstracted to create a base class of the Mixin style, which allows the derived class to inherit a single specific capability (here "set the class exclusive New-Handler"), abstract The base class as a template class to improve reusability.
Template <typename T> // a base class in the Mixin style to support the exclusive set_new_handlerclass 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 );... // other operator new versions: Private: static STD: new_handler currenthandler;}; Template <typename T> STD: new_handlernewhandlersupport <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 );} // initialize each currenthandler as nulltemplate <typename T> STD: new_handler newhandlersupport <t >:: currenthandler = 0;
For a specific class, it is easy to add the exclusive set_new_handler: inheritance.
Class Widget: Public newhandlersupport <widget> {... // same as the previous one, but it does not need to declare set_new_handler or operator new };
6. The old operator new returns NULL after memory allocation fails. to be compatible with the old Code, C ++ provides
Operator new in the first form, called the nothrow form, uses the nothrow object (defined in the header <New>
File ). We recommend that you do not use it.