new and delete operators?This is in continuation of Overloading new and delete in
... 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 installednew_handlerusing theset_new_handlerfunction (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 classstd::bad_alloc(18.4.2.1) or a class derived fromstd::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