Whether it is successful or not, uninstall it.Widget::current
And install and callWidget::operator new
The previous global error handling function. Operator newWe use RAII class to ensure that the original global error handling function can be restored, so that exceptions can continue to spread. For more information about RAII, see Item 13. First, write a RAII class that maintains the error handling function:
Class NewHandlerHolder {public: explicit NewHandlerHolder (std: new_handler nh): handler (nh ){}~ NewHandlerHolder () {std: set_new_handler (handler);} private: std: new_handler handler; NewHandlerHolder (const HandlerHolder &); // disable the copy const NewHandlerHolder & operator = (const NewHandlerHolder &); // disable the value assignment operator };
ThenWidget::operator new
Is actually very simple:
Void * Widget: operator new (std: size_t size) throw (std: bad_alloc) {NewHandlerHolder h (std: set_new_handler (current); return :: operator new (size); // call global new, throwing an exception or success} // function call ends, original error handler function recovers
Use Widget: operator newCustomer useWidget
The method also conforms to the Convention of the basic data type:
Void outOfMem (); Widget: set_new_handler (outOfMem); Widget * p1 = new Widget; // if it fails, outOfMemstring * ps = new string will be called; // if it fails, the Global new-handling function will be called. If there is no such function, the Widget: set_new_handler (0) will be absent ); // set the exception handling function of the Widget to empty Widget * p2 = new Widget; // If the Widget fails, an exception is thrown immediately.
General base classAfter carefully observing the above Code, it is easy to find that the logic of the custom "new-handler" is actuallyWidget
Is irrelevant. We can extract these logics as a template base class:
template
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 current;};template
std::new_handler NewHandlerSupport
::current = 0;template
std::new_handler NewHandlerSupport
::set_new_handler(std::new_handler p) throw(){ std::new_handler old = current; current = p; return old;}template
void * NewHandlerSupport
::operator new(std::size_t size) throw(std::bad_alloc){ NewHandlerHolder h(std::set_new_handler(current)); return ::operator new(size);}
With this template base classWidget
Add "new-handler" to support only public inheritance:
class Widget: public NewHandlerSupport
{ ... };
ActuallyNewHandlerSupport
Implementation and template parametersT
It is completely irrelevant. The template parameter is added becausehandler
Is a static member so that the compiler can generatehandler
Instance.
Nothrow newBefore December 31, 1993operator new
Will return when the failurenull
Instead of throwing an exception. Today's C ++ still supports such nothrowoperator new
:
Widget * p1 = new Widget; // The bad_alloc exception assert (p1! = 0); // This always sets up the Widget * p2 = new (std: nothrow) Widget; if (p2 = 0 )... // p2 = 0 upon failure
"Nothrow new" only applies to memory allocation errors. The constructor can also throw an exception, which cannot be guaranteed to benew
The statement is "nothrow.