From std::set_new_handler
The new-handler function is the function called by allocation functions whenever a memory allocation attempt fails. Its intended purpose is one of three things:
Will the following overload gurantees anything ?
void * operator new(std::size_t size) throw(std::bad_alloc){
while(true) {
void* pMem = malloc(size);
if(pMem)
return pMem;
std::new_handler Handler = std::set_new_handler(0);
std::set_new_handler(Handler);
if(Handler)
(*Handler)();
else
throw bad_alloc();
}
}
std::set_new_handler
doesn't make memory available, it sets a new-handler function to be used when allocation fails.
A user-defined new-handler function might be able to make more memory available, e.g. by clearing an in-memory cache, or destroying some objects that are no longer needed. The default new-handler does not do this, it's a null pointer, so failure to allocate memory just throws an exception, because the standard library cannot know what objects in your program might not be needed any more. If you write your own new handler you might be able to return some memory to the system based on your knowledge of the program and its requirements.
Here is a working example illustrating the functioning of custom new handlers.
#include <iostream>
#include <new>
/// buffer to be allocated after custom new handler has been installed
char* g_pSafetyBuffer = NULL;
/// exceptional one time release of a global reserve
void my_new_handler()
{
if (g_pSafetyBuffer) {
delete [] g_pSafetyBuffer;
g_pSafetyBuffer = NULL;
std::cout << "[Free some pre-allocated memory]";
return;
}
std::cout << "[No memory to free, throw bad_alloc]";
throw std::bad_alloc();
}
/// illustrates how a custom new handler may work
int main()
{
enum { MEM_CHUNK_SIZE = 1000*1000 }; // adjust according to your system
std::set_new_handler(my_new_handler);
g_pSafetyBuffer = new char[801*MEM_CHUNK_SIZE];
try {
while (true) {
std::cout << "Trying another new... ";
new char[200*MEM_CHUNK_SIZE];
std::cout << " ...succeeded.\n";
}
} catch (const std::bad_alloc& e) {
std::cout << " ...failed.\n";
}
return 0;
}
I do not suggest the demonstrated strategy for production code, it may be too heavy to predict, how many allocations will succeed after your new_handler is called once. I observed some successful allocations on my system (play with the numbers to see what happens on yours). Here's one possible output:
Trying another new... ...succeeded.
Trying another new... ...succeeded.
Trying another new... ...succeeded.
Trying another new... ...succeeded.
Trying another new... ...succeeded.
Trying another new... [Free some pre-allocated memory] ...succeeded.
Trying another new... ...succeeded.
Trying another new... ...succeeded.
Trying another new... ...succeeded.
Trying another new... [No memory to free, throw bad_alloc] ...failed.
Process returned 0 (0x0) execution time : 0.046 s
Press any key to continue.
Instead, from my perspective, do the release of a safety buffer only for terminating your program in a safe way. Even proper exception handling needs memory, if there isn't enough available, abort()
is called (as I learned recently).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With