Effective C + + clause 49 Understanding the behavior of new handler

Source: Internet
Author: User

1. When operator new fails to meet a memory allocation requirement, it invokes a client-specified error handler (it throws an exception if the customer does not specify it), called New-handler. To specify this function to handle out of memory, the client must call set_ New_handler, that's a standard library function declared in <new>:

namespace std{    void (*new_handler) ();     Throw ();}
View Code

New_handler is a typedef whose type is a function pointer to a function that has both a parameter and a return value of void, and the Set_new_handler new_handler parameter is used to specify the function to invoke when sufficient memory cannot be allocated Set_new_ The function pointer returned by handler points to a function that was previously used to handle insufficient memory when it is about to be replaced, and Set_new_handler uses the following:

// Outofmem is a function that should be called when enough memory cannot be allocated void Outofmem () {    std::cerr<<"Unable to satisfy  request for mempry/n" <<Endl;    Std::abort ();} int Main () {    std::set_new_handler (outofmem);     int* pbigdataarray=newint[1000000000];    ...}
View Code

If operator new cannot allocate the space required for 1 billion int variables, it does not immediately throw an exception, but instead calls Outofmem because Outofmem is already set to the default New-handler.

A well-designed new-handler should do the following things:

1). Let more memory be used. One of the strategies for achieving this is to allocate a large chunk of memory at the beginning of the program and return it to the program when the New-handler is first called (indicating insufficient memory).

2). Install another new-handler, if the current new-handler cannot get more memory but it knows another new-handler has this ability, it can call Set_new_ Handler set that New-handler as the default New-handler so that the next operator new call New-handler is the newest one (so one strategy is to make the current New-handler modify its own behavior, The method is to let it modify the static data that will affect the current New-handler behavior, namespace data, global data, etc.)

3). Remove New-handler. Pass a null pointer to Set_new_handler and throw an exception when operator new allocates memory is unsuccessful.

4). Throws an Bad_alloc (or derived from Bad_alloc) exception. Such exceptions are not captured by operator new and are then passed to memory demands.

5). Do not return. Call abort or exit. (as Outofmem did)

2. Sometimes for different classes, you want to handle operator new memory allocation failure with a different new-handler. Although C + + does not support class-specific new-handler, it is possible to implement this behavior on its own, simply by giving each class its own set_ New_handler and operator new. Where Set_new_handler is used to set the class-specific new-handler,operator New ensures that you replace the global New-handler with class-specific New-handler when allocating class memory, and replaces the default New-handler with global when the class-specific New-handler completes its duties New-handler.

Assuming that the memory allocation failure of the Widget class is to be handled, the above policy is implemented as follows:

classwidget{ Public:    StaticStd::new_handler Set_new_handler (Std::new_handler p)Throw(); StaticSTD::operator New(std::size_t size)Throw(std::bad_alloc);Private:    StaticStd::new_handler Currenthandler;} Std::new_handler Widget::currenthandler=0; Std::new_handler Widget::set_new_handler (Std::new_handler p)Throw() {Std::new_handler Oldhandler=Currenthandler; Currenthandler=p; returnOldhandler;}
View Code

Finally, the widget's operator new does the following things:

1). Call the standard Set_new_handler, inform the widget of the error handler, and the widget's new-handler install bit global New-handler.

2). Call global operator new to actually allocate memory, and if the allocation fails, global operator new calls the widget's New-handler because that function has just been installed as New-handler. If global operator new does not eventually allocate enough memory to throw a Bad_alloc exception, in which case the widget's operator new must restore the original global new-handler and then propagate the exception, which would require the idea of clause 13 --to resource management objects.

3). Finally, if global operator new succeeds in allocating the memory used by a Widget object, the widget's operator new should return a pointer to the assignment.

In conjunction with the Resource Management class implementation Widget::operator new is as follows:

classnewhandlerholder{ Public: Explict newhandlerholder (std::new_handler NH): Handler (NH) {}~Newhandler () {Std::set_new_handler (handler);}Private: Std::new_handler handler; //for saving global New-handlerNewhandlerholder (Constnewhandlerholder&); Newhandlerholder&operator=(Constnewhandlerholder&);}void* Widget::operator New(std::size_t size)Throw(std::bad_alloc) {Newhandlerholder h (Std::set_new_handler (Currenthandler));//install New-handler and enable H to save global New-handler    return::operator New(size);//H Restore global new-handler at destructor}
View Code

The widget's customers use their new-handler like this:

void Ourofmem (); Widget::set_new_handler (OUTOFMEM); Widget* pw1=new widget;  // If the memory allocation fails, the call is OUTOFMEMstd::string *ps=newstring;   // If the memory allocation fails, the call is global New-handler Widget::set_new_handler (0); Widget* pw2=new widget;  // throws an exception directly if memory allocation fails
View Code

The above code has a generalization, so you might consider setting it as a template, inheriting from other classes, and inheriting this ability to set the exclusive new-handler of classes:

Template<typename t>classnewhandlersupport{ Public:    StaticStd::new_handler Set_new_handler (Std::new_handler p)Throw(); StaticSTD::operator New(std::size_t size)Throw(Std::bad_alloc); ...Private:    StaticStd::new_handler Currenthandler;} Template<typename t>Std::new_handler Newhandlersupport<t>::currenthandler=0; template<typename t>Std::new_handler Newhandlersupport<t>::set_new_handler (Std::new_handler p)Throw() {Std::new_handler Oldhandler=Currenthandler; Currenthandler=p; returnOldhandler;} Template<typename t>void* NEWHANDLERSUPPORT&LT;T&GT;::::operator New(std::size_t size)Throw(std::bad_alloc) {Newhandlerholder h (Std::set_new_handler (Currenthandler));//install New-handler and enable H to save global New-handler    return::operator New(size);//H Restore global new-handler at destructor}
View Code

With this class template, you can add Set_new_handler support for widgets and other classes-as long as the widgets are inherited from Newhandlersupport<widget>:

class Widget: public newhandlersupport<widget>{    ...}
View Code

The class template Newhandlersupport looks rather strange because the parameter T is never used, and the parameter T is actually used to distinguish between different derived classes, Each class that inherits from Newhandlersupport has its own independent static member variable Currenthandler. The widget inherits from a class template with a widget parameter, which is allowed by C + +, and has its own name--"Weird looping pattern" (curiously recurring template pattern; CRTP).

The construction of the Newhandlersupport class template makes it easy to add a new-handler of their own to any class, but the inheritance of the "mixin" style can also lead to multiple inheritance disputes.

3. Until 1993, C + + required operator new to return NULL when sufficient memory could not be allocated, although a new generation of operator should throw Bad_alloc exceptions, but the original "nothrow" form of operator New is still saved, defined in the header file <new>, and the method is called as follows:

class widget{...} Widget* pw1=new widget;

Because the new widget expression above occurs two things: Call the nothrow version of operator new, call the widget's default constructor, so although the nothrow version of operator new guarantees that no exception is thrown, However, this does not prevent the widget's default constructor from throwing an exception, so nothrow new cannot prevent the new expression from throwing an exception.

Effective C + + clause 49 Understanding the behavior of new handler

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.