How should I write ISO C++ Standard conformant custom new and delete operators?

前端 未结 4 1379
旧巷少年郎
旧巷少年郎 2020-11-22 17:07

How should I write ISO C++ standard conformant custom new and delete operators?

This is in continuation of Overloading new and delete in

4条回答
  •  甜味超标
    2020-11-22 17:44

    Part II

    ... continued

    Given the behavior of operator new from the example, a well designed new_handler must do one of the following:

    Make more memory available: This may allows the next memory allocation attempt inside operator new's loop to succeed. One way to implement this is to allocate a large block of memory at program start-up, then release it for use in the program the first time the new-handler is invoked.

    Install a different new-handler: If the current new-handler can't make any more memory available, and of there is another new-handler that can, then the current new-handler can install the other new-handler in its place (by calling set_new_handler). The next time operator new calls the new-handler function, it will get the one most recently installed.

    (A variation on this theme is for a new-handler to modify its own behavior, so the next time it's invoked, it does something different. One way to achieve this is to have the new-handler modify static, namespace-specific, or global data that affects the new-handler's behavior.)

    Uninstall the new-handler: This is done by passing a null pointer to set_new_handler. With no new-handler installed, operator new will throw an exception ((convertible to) std::bad_alloc) when memory allocation is unsuccessful.

    Throw an exception convertible to std::bad_alloc. Such exceptions are not be caught by operator new, but will propagate to the site originating the request for memory.

    Not return: By calling abort or exit.

    To implement an class-specific new_handler we have to provide a class with its own versions of set_new_handler and operator new. The class's set_new_handler allows clients to specify the new-handler for the class (exactly like the standard set_new_handlerallows clients to specify the global new-handler). The class's operator new ensures that the class-specific new-handler is used in place of the global new-handler when memory for class objects is allocated.


    Now that we understand new_handler & set_new_handler better we are able to modify the Requirement #4 suitably as:

    Requirement #4 (Enhanced):
    Our operator new should try to allocate memory more than once, calling the new-handling function after each failure. The assumption here is that the new-handling function might be able to do something to free up some memory. Only when the pointer to the new-handling function is null does operator new throw an exception.

    As promised, the citation from the Standard:
    Section 3.7.4.1.3:

    An allocation function that fails to allocate storage can invoke the currently installed new_handler(18.4.2.2), if any. [Note: A program-supplied allocation function can obtain the address of the currently installed new_handler using the set_new_handler function (18.4.2.3).] If an allocation function declared with an empty exception-specification (15.4), throw(), fails to allocate storage, it shall return a null pointer. Any other allocation function that fails to allocate storage shall only indicate failure by throw-ing an exception of class std::bad_alloc (18.4.2.1) or a class derived from std::bad_alloc.

    Armed with the #4 requirements, let us attempt the pseudo code for our new operator:

    void * operator new(std::size_t size) throw(std::bad_alloc)
    {  
       // custom operator new might take additional params(3.7.3.1.1)
    
        using namespace std;                 
        if (size == 0)                     // handle 0-byte requests
        {                     
            size = 1;                      // by treating them as
        }                                  // 1-byte requests
    
        while (true) 
        {
            //attempt to allocate size bytes;
    
            //if (the allocation was successful)
    
            //return (a pointer to the memory);
    
            //allocation was unsuccessful; find out what the current new-handling function is (see below)
            new_handler globalHandler = set_new_handler(0);
    
            set_new_handler(globalHandler);
    
    
            if (globalHandler)             //If new_hander is registered call it
                 (*globalHandler)();
            else 
                 throw std::bad_alloc();   //No handler is registered throw an exception
    
        }
    
    }
    

    Continuation 2

提交回复
热议问题