Actually, there's a simple solution: replace operator new with one which does throw on allocation failure. (The linked code is standard C++ and may need tweaks for your compiler. You can use malloc for allocate_from_some_other_source and free for deallocate_from_some_other_source.)
Old answer
(These replacements do require changes in calling code, simply because the C++ grammar is structured so that's unavoidable. However, they're written to require minimal changes in order to be used as logical drop-in replacements. The real solution is upgrading to a version of MSVC from the last 7 years or so. MSVC6, which it sounds like you're using, was actually released before the C++ standard in 1998.)
Solving for the general case is hard, but here's an approximation:
struct Thrower { // needs a better name
void* p;
Thrower(void* p) : p(p) {
if (!p) throw std::bad_alloc();
}
~Thrower() {
if (std::uncaught_exception()) operator delete(p);
// this is true when the object's ctor throws
}
operator void*() const { return p; }
};
int main() {
int* p = new (Thrower(operator new(sizeof(int))) int(42);
// int is a placeholder type, but shows you can still pass ctor parameters
// with a macro becomes:
#define MYNEW(T) new (Thrower(operator new(sizeof(T))) T
int* p = MYNEW(int)(42);
}
For known parameters, you can avoid a macro and keep it simple:
template<class T>
T* my_new() {
T* p = new T();
if (!p) throw std::bad_alloc();
return p;
}
template<class T>
T* my_new(T const& value) {
T* p = new T(value);
if (!p) throw std::bad_alloc();
return p;
}
int main() {
int* p = my_new<int>();
int* p2 = my_new<int>(*p);
}