I know that according to C++ standard in case the new fails to allocate memory it is supposed to throw std::bad_alloc exception. But I have heard that some compilers such as VC6 (or CRT implementation?) do not adhere to it. Is this true ? I am asking this because checking for NULL after each and every new statement makes code look very ugly.
Based on the C++ spec, it will always throw std::bad_alloc when you use just plain new with no params, but of course there can be some non compliant compilers.
I would not code to be compliant with non c++ compliant compilers though. VC6 being one of them in this respect.
It is good practice though to always set your pointer to NULL after you delete them. So because of that, checking for NULL is still needed.
That being said, here are a couple options to cleaning up your code:
Option 1: Setting your own new handler
A safe way to clean up your code would be to call: set_new_handler first.
Then you could check for NULL in your handler and throw std::bad_alloc there if NULL is returned.
If you like exceptions better, then this is your best bet. If you like to return NULL better then you can also do that by doing a catch inside your new handler.
Option 2: Using overloaded new
The c++ standard header file defines a struct nothrow which is empty. You can use an object of this struct inside new to get its overloaded version that always returns NULL.
void* operator new (size_t size, const std::nothrow_t &);
void* operator new[] (void *v, const std::nothrow_t &nt);
So in your code:
char *p = new(std::nothrow) char[1024];
VC6 was non-compliant by default in this regard. VC6's new
returned 0
(or NULL
).
Here's Microsoft's KB Article on this issue along with their suggested workaround using a custom new
handler:
If you have old code that was written for VC6 behavior, you can get that same behavior with newer MSVC compilers (something like 7.0 and later) by linking in a object file named nothrownew.obj
. There's actually a fairly complicated set of rules in the 7.0 and 7.1 compilers (VS2002 and VS2003) to determine whether they defaulted to non-throwing or throwing new
: http://msdn.microsoft.com/en-us/library/kftdy56f(VS.71).aspx
It seems that MS cleaned this up in 8.0 (VS2005): http://msdn.microsoft.com/en-us/library/kftdy56f.aspx - now it always defaults to a throwing new unless you specifically link to nothrownew.obj
.
Note that you can specify that you want new
to return 0
instead of throwing std::bad_alloc
using the std::nothrow
parameter:
SomeType *p = new(std::nothrow) SomeType;
This appears to work in VC6, so it could be a way to more or less mechanically fix the code to work the same with all compilers so you don't have to rework existing error handling.
I'd like to add the (somewhat controversial) opinion that checking for NULL after an allocation attempt is pretty much an exercise in futility. If your program ever runs into that situation, chances are you can't do much more than exiting fast. It's very likely that any subsequent allocation attempt will also fail.
Without checking for NULL, your subsequent code would attempt to dereference a NULL pointer, which tends to exit the program fast, with a relatively unique (and easily debuggable) exit condition.
I'm not trying to talk you out of checking for NULL, it's certainly conscientious programming. But you don't gain much from it, unless in very specific cases where you can perhaps store some recovery information (without allocating more memory), or free less important memory, etc. But those cases will be relatively rare for most people.
Given this, I'd just trust the compiler to throw bad_alloc, personally - at least in most cases.