Testing for failed memory allocation can be done with code such as the following:
int *pi = new int[BIG_NUMBER];
if( pi == 0 )
{
cerr << "Insufficient memory" << endl;
return -1;
}
In some circumstances, corrective action can be taken during memory allocation and the request can be fulfilled. To gain control when the global operator new function fails, use the _set_new_handler function (defined in NEW.H) as follows:
#include <stdio.h>
#include <new.h>
// Define a function to be called if new fails to allocate memory.
int MyNewHandler( size_t size )
{
clog << "Allocation failed. Coalescing heap. << endl;
// Call a fictitious function to recover some heap space.
return CoalesceHeap();
}
main()
{
// Set the failure handler for new to be MyNewHandler.
_set_new_handler( MyNewHandler );
int *pi = new int[BIG_NUMBER];
return 0;
}
In the preceding example, the first statement in main sets the new handler to MyNewHandler. The second statement tries to allocate a large block of memory using the new operator. When the allocation fails, control is transferred to MyNewHandler. The argument passed to MyNewHandler is the number of bytes requested. The value returned from MyNewHandler is a flag indicating whether allocation should be retried: a nonzero value indicates that allocation should be retried, and a zero value indicates that allocation has failed.MyNewHandler prints a warning message and takes corrective action. If MyNewHandler returns a nonzero value, the new operator retries the allocation. Only when MyNewHandler returns a 0 does the new operator stop trying and return a zero value to the program.
The _set_new_handler function returns the address of the previous new handler. Therefore, if a new handler needs to be installed for a short time, the previous new handler can be reinstalled using code such as the following:
#include <new.h>
...
_PNH old_handler = _set_new_handler( MyNewHandler );
// Code that requires MyNewHandler.
...
// Reinstall previous new handler.
_set_new_handler( old_handler );
A call to _set_new_handler with an argument of 0 causes the default new handler to be reinstalled.
The new handler you specify can have any name, but it must be a function returning type int (nonzero indicates the new handler succeeded, and zero indicates that it failed). The argument list is described in Tables 11.6 and 11.7.
If a user-defined operator new is provided, the new handler functions are not automatically called on failure.
In Microsoft C++, objects can be allocated on the default heap, the near heap, the far heap, the huge heap, or a based heap. New handlers for these heaps can be set using the functions declared in NEW.H, which are listed in Table 11.6.
Table 11.6 Functions Used to Set New Handlers
Function Name | New Handler That Is Set | Prototype |
_set_new_handler | Default new handler | _PNH _set_new_handler ( _PNH ); |
set_nnew_handler | New handler for objects allocated on the near heap | _PNH _set_nnew_handler ( _PNH ); |
Table 11.6 (continued)
Function Name | New Handler That Is Set | Prototype |
_set_fnew_handler | New handler for objects allocated on the far heap | _PNH _set_fnew_handler ( _PNH ); |
_set_hnew_handler | New handler for objects allocated on the huge heap | _PNHH _set_hnew_handler ( _PNHH ); |
_set_bnew_handler | New handler for objects allocated on the based heap | _PNHB _set_bnew_handler ( _PNHB ); |
To facilitate easy declaration of the new handlers, three types are defined. See Table 11.7.
Table 11.7 List of New-Handler Types
Type | Meaning |
_PNH | Pointer to a function that returns type int and takes a single argument of type size_t. |
_PNHH | Pointer to a function that returns type int and takes arguments of type unsigned long (the number of elements) and type size_t (the size of a given element). |
_PNHB | Pointer to a function that returns type int and takes arguments of type __segment (the segment base) and of type size_t. |
By using the appropriate “set new handler” function, you can trap memory-allocation failures for default, near, far, huge, and based objects.¨