set_new_handler, a standaed library function declared in <new>
namespace std {
typedef void (*new_handler)();
new_handler set_new_handler(new_handler p) throw();
}
void outOfMem() {
std::cerr << "Unable to satisfy request for memory\n";
std::abort();
}
class Widget {
public:
static std::new_handler set_new_handler(std::new_handler p) throw();
sttic void * operator new(std::size_t size) throw(std::bad_alloc);
private:
static std::new_handler currentHandler;
};
// static class members must be define outside the class
// defination(unless they're const and integral)
std::new_handler Widget::currentHandler = 0;
// this is what the standard version of set_new_handler does
std::new_handler Widget::set_new_handler(std::new_handler p) throw() {
std::new_handler oldHandler = currentHandler;
currentHandler = p;
return oldHandler;
}
// RAII(Resource Acquisition Is Initialization)
class NewHandlerHolder {
public:
explicit NewHandlerHolder (std::new_handler nh): handler(nh) { }
~NewHandlerHolder() {
std::set_new_handler(handler);
}
private:
std::new_handler handler;
NewHandlerHolder(const NewHandlerHolder&);
NewHandlerHolder&
operator=(const NewHandlerHolder&);
};
void* Widget::operator new(std::size_t size) throw(std::bad_alloc) {
NewHandlerHolder
h(std::set_new_handler(currentHandler));
return ::operator new(size);
}
// set outOfMem as Widget's new-handling funcion.
// if memory allocation fails, call outOfMem
void outOfMem();
Widget::set_new_handler(outOfMem);
Widget *pwl = new Widget;
// if memory allocation fails, call the global new-handing
// funcion
std::string *ps = new std::string;
// if mem.alloc fails, throw an exception immediately.
// (There is no new-handing function for class Widget.)
Widget::set_new_handler(0);
Widget *pw2 = new Widget;
template<typename T>
class NewHandlerSupport {
public:
static std::new_handler set_new_handler(std::new_handler p) throw();
static void* operator new(std::size_t size) throw(std::bad_alloc);
private:
static std::new_handler currentHandler;
};
template<typename>
std::new_handler
NewHandlerSupport<T>::set_new_handler(std::new_handler p) throw() {
std::new_handler olderHandler = currentHandler;
currentHandler = p;
return oldHandler;
}
template<typename T>
void* NewHandlerSuppor<T>::operator new(std::size_t size) throw(std::bad_alloc) {
NewHandlerHolder h(std::set_new_handler(currentHandler));
return ::operator new(size);
}
// this initializes each currentHandler to null
template<typename T>
std::new_handler NewHandlerSuppor<T>::currentHandler = 0;
class Widget: public NewHandlerSupport<Widget> {
// as before, but without declarations for set_new_handler or operator new
...
}
// throw bad_alloc if allocation fails
class Widget {... };
Widget *pw1 = new Widget;
// this test must fail
if (pw1 == 0) ...
// returns 0 if allocation for the Widget fails
Widget *pw2 = new(std::nothrow) Widget;
// this test must succeed
if (pw2 == 0) ...