Professional C__ - Marc Gregoire [170]
ptr = new(nothrow) int[numInts];
if (ptr == nullptr) {
cerr << __FILE__ << "(" << __LINE__
<< "): Unable to allocate memory!" << endl;
// Handle memory allocation failure.
return;
}
// Proceed with function that assumes memory has been allocated.
Code snippet from NewFailures\Nothrow.cpp
The syntax is a little strange: you really do write “nothrow” as if it’s an argument to new (which it is).
Customizing Memory Allocation Failure Behavior
C++ allows you to specify a new handler callback function. By default, there is no new handler, so new and new[] just throw bad_alloc exceptions. However, if there is a new handler, the memory allocation routine calls the new handler upon memory allocation failure instead of throwing an exception. If the new handler returns, the memory allocation routines attempt to allocate memory again, calling the new handler again if they fail. This cycle could become an infinite loop unless your new handler changes the situation with one of four alternatives. Practically speaking, some of the four options are better than others. Here is the list with commentary:
Make more memory available. One trick to expose space is to allocate a large chunk of memory at program start-up, and then to free it in the new handler. A practical example is when you hit an allocation error and you need to save the user state so no work gets lost. The key is to allocate a block of memory at program start-up large enough to allow a complete document save operation. When the new handler is triggered, you free this block, save the document, restart the application and let it reload the saved document.
Throw an exception. new and new[] have throw lists that say they will throw exceptions only of type bad_alloc. So, unless you want to create a call to unexpected(), if you throw an exception from the new handler, throw bad_alloc or a subclass. For example, when your new handler is triggered, you can throw a document_recovery_alloc exception which inherits from bad_alloc. You can catch this exception somewhere in your application and trigger the document save operation and restart of the application.
Set a different new handler. Theoretically, you could have a series of new handlers, each of which tries to create memory and sets a different new handler if it fails. However, such a scenario is usually more complicated than useful.
Terminate the program. Your new handler can log an error message and throw an agreed-upon exception such as PleaseTerminateMe. In your top-level function, for example main(), you catch this exception and handle it by returning from the top-level function. Never explicitly terminate the program by using exit() or abort(), only by returning from the top-level function. If there are some memory allocations that can fail but still allow your program to succeed, you can simply set the new handler back to its default of nullptr temporarily before calling new in those cases.
If you don’t do one of these four things in your new handler, any memory allocation failure will cause an infinite loop.
You set the new handler with a call to set_new_handler(), declared in the class PleaseTerminateMe { }; void myNewHandler() { cerr << __FILE__ << "(" << __LINE__ << "): Unable to allocate memory." << endl; throw PleaseTerminateMe(); } Code snippet from NewFailures\NewHandler.cpp The new handler must take no arguments and return no value. This new handler throws a PleaseTerminateMe exception like suggested in the fourth bullet in the preceding list. You can set the new handler like this: int main() { try { // Set the new new_handler and save the