"Effective C + +": Clause 49: Understanding the behavior of New-handler

Source: Internet
Author: User

C + + memory is managed manually by programmers, unlike Java or. NET, which has a garbage collection mechanism. C + + memory management is primarily the allocation routines and return routines (allocation and deallocation routines), operator new and operator Delete, and a mated role New-handler. When it comes to arrays, the operator new and operator delete mentioned above will change to operator new[] and operator delete[].

Memory management is more complex in a multithreaded environment because heap is a global resource that can be changed, and multiple threads accessing the same resource will have race conditions (race state). Use static type variables to be more careful. If you do not have proper synchronization control (synchronization), you may break the heap data structure when using the lock-free (lock-free) algorithm or by carefully preventing concurrent access (concurrent access).

Finally, note that the heap used by the STL container is managed by the allocator object owned by the container (allocator objects), not directly managed with new and delete.

Article 49: Understanding the behavior of New-handler

When operator new fails to satisfy a memory allocation, it is thrown one time. It used to return a null pointer, and now some legacy compilers do the same.

Before operator new throws an exception, a client-specified error handler is called First: New-handler. (This is not all, operator new is more complex, see * * clause **51). The client uses Set_new_handler to specify the function "to handle out of memory", which is the standard library function declared in new

namespacestd{        typedefvoid(*new_handler)();        throw();    }

New_handler is a function pointer that has no arguments or returns anything. Set_new_handler is to set a new_handler and return a new_handler function, and the New_handler returned is the Set_new_handler function that is being executed before New-handler is called. The throw behind is an exception detail indicating that the function does not throw an exception. You can use this

    void outOfMem()    {        std::cerr<<"Unable to satisfy request for memoryn";        std::abort();    }    int main()    {        std::set_new_handler(outOfMem);        int *pBigDataArray=newint[100000000L];        ……    }

If operator new cannot allocate enough space for 100 million integers, Outofmem will be called.

When operator new fails to satisfy the memory request, it constantly calls New-handler until enough memory is found. Repeated calls to the code are discussed in * * clause **51. Here first, well-designed New-handler must do the following things;

    • allow more memory to be used. this can cause the next memory allocation action within operator new to be successful. One approach is to allocate a large chunk of memory at the beginning of the program and release it when New-handler is first called.
    • install another new-handler. when the current new-handler cannot get more memory, it may not be until which New-handler has this ability.
    • Remove the New-handler. The null pointer is passed to Set_new_handler, and once no new-handler,operator new is installed, an exception is thrown when the memory allocation is unsuccessful.
    • throws an exception Bad_alloc (or derived from Bad_alloc). Such exceptions are not captured by operator new and are therefore not propagated to memory demands.
    • does not return. usually abort or exit.

Sometimes, we want to handle memory allocation failures and class-related situations. For example

    class X{    public:        staticvoidoutOfMemory();        ……    };    class Y{    public:        staticvoidoutOfMemory();        ……    };    X* p1=new X;//分配不成功,调用X::outOfMemory    Y* p2=new Y;//分配不成功,调用Y::outOfMemory

C + + does not support class-specific new-handler, but we can implement this behavior ourselves. Let each class provide its own set_new_handler and operator new. ................................................................................................

Now it's time to deal with the failure of the widget class memory allocation. First, there is a call function that operator new cannot allocate enough memory for the widget, that is, the New_handler function

 classwidget{ 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::set_new_handler (STD:: New_handler p)Throw()    {STD:: New_handler Oldhandler=currenthandler;        Currenthandler=p;    REUTRN Oldhandler; }

The operator new for the

widget does the following:
1, call the standard Set_new_handler, and tell the widget about the error handling function. This installs the widget's New-handler as global New-handler.
2, call global operator new, if it fails, global operator new will call the widget's New-handler because of the first step. If global operator new eventually fails to allocate enough memory, a Bad_alloc exception is thrown. The widget operator new to restore the original global New-handler, and then propagate the exception.
3, if the global operator new call succeeds, the widget's operator new returns a pointer to the allocated memory. The widget destructor manages the global New-handler, which restores the global New-handler before the widget's operator new is called.

    class NewHandlerHolder{    public:        explicitNewHandlerHolder(std::new_handler nh)        :handlere(nh){}        ~NewHandlerHolder()        { std::set_new_handler(handler); }    private:        std::new_handler handler;        NewHandlerHolder&(const NewHandlerHolder&);//防止copying        operator-(const NewHandlerHolder&);    };

This makes the widget's operator new implementation simple

    void* Widget::operatornew(stdthrow(std::bad_alloc)    {        NewHandlerHolder h(std::set_new_handler(currentHandler));//安装Widget的new-handler        return ::operatornew(size);    }

Widget customers should use their new-handling like this

 void  outofmem (); Widget::set_new_handler  (OUTOFMEM); //set Outofmem function as widget  Widget*  pw1=  new  widgets; //memory allocation failed, call Outofmem  std::string  *  ps=  new  std ::string ; //memory allocation failure call Global new-handling (if any)  Widget::set_new_handler  (0 ); //set widget exclusive new-handling is null  Widget*  pw2=  new  widgets; //memory allocation failure immediately throws an exception  

The class code that implements this scheme is basically the same, and it is a good way to reuse a base class base classes. You can use a template base class so that each derived class will get the class data copy of the entity that is different from each other. This base class allows its derived class to inherit it to get Set_new_handler and operator new,template parts to ensure that each derived Class obtains an Currenthandler member variable with an entity that is mutually dissimilar.

 Template<TypeNameT>classnewhandlersupport{ 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<TypeNameT>STD:: New_handler Newhandlersupport<t>::set_new_handler (STD:: New_handler p)Throw()    {STD:: New_handler Oldhandler=currenthandler; Currenthandler=p;returnOldhandler; }Template<TypeNameT>void* NEWHANDLERSUPPORT&LT;T&GT;::operator New(STD:: size_t size)Throw(STD:: Bad_alloc) {Newhandlerholder h (STD:: Set_new_handler (Currenthandler);return::operator New(size); }//Initialize each of the Currenthandler to null    Template<TypeNameT>STD:: New_handler newhandlersupport<t>::currenthandler=0; With thisclass Template, it's easy to add Set_new_handler to the widget.classWidgets: PublicNewhandlersupport<widget>{...};

The type T is never used in the template base class. Because Currenthandler is a static type, using a template would mean that each class has its own currenthandler. If you are using multiple inheritance, be aware of the content mentioned in * * clause **40.

operator new allocation failure in C + + throws an exception bad_alloc, but the old standard is to return a null pointer. This form of the old standard is nothrow form.

class Widget{};    Widget* pw1=new Widget;//分配失败,抛出bad_alloc    if(pw1==null)//判断是否分配成功。但是这个测试失败    Widget* pw2=new(std::nothrow)Widget;//分配失败,返回null    if(pw2==null)//可以侦测

The new (Std::nothrow) widget takes two things, the first allocates memory to the Widget object, and if it fails, returns a null pointer. Second, if it succeeds, call the widget's constructor, but what this constructor does, nothrow new does not know, is likely to open up memory again. If the constructor uses operator new to open up memory, it is still possible to throw an exception and propagate. Using nothrow new only guarantees that operator new does not throw an exception, and there is no guarantee that an expression like the new (Std::nothrow) widget does not throw an exception. Therefore, there is no need to use nothrow.

Summarize

    • Set_new_handler allows a client to specify a function that is called when the memory allocation is not met.
    • Nothrow New is a fairly limited tool because it only applies to memory allocations, and subsequent constructor calls are likely to throw exceptions.

"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.