I am a student and I have small knowledge on C++, which I try to expand. This is more of a philosophical question.. I am not trying to implement something.
Since
I think that the rationale behind why you'd use the regular new
instead of the nothrow
new is connected to the reason why exceptions are usually preferred to explicitly checking the return value of each function. Not every function that needs to allocate memory necessarily knows what to do if no memory can be found. For example, a deeply-nested function that allocates memory as a subroutine to some algorithm probably has no idea how what the proper course of action to take is if memory can't be found. Using a version of new
that throws an exception allows the code that calls the subroutine, not the subroutine itself, to take a more appropriate course of action. This could be as simple as doing nothing and watching the program die (which is perfectly fine if you're writing a small toy program), or signalling some higher-level program construct to start throwing away memory.
In regards to the latter half of your question, there actually could be things you could do if your program ran out of memory that would make memory more available. For example, you might have a part of your program that caches old data, and could tell the cache to evict everything as soon as resources became tight. You could potentially page some less-critical data out to disk, which probably has more space than your memory. There are a whole bunch of tricks like this, and by using exceptions it's possible to put all the emergency logic at the top of the program, and then just have every part of the program that does an allocation not catch the bad_alloc and instead let it propagate up to the top.
Finally, it usually is possible to throw an exception even if memory is scarce. Many C++ implementations reserve some space in the stack (or some other non-heap memory segment) for exceptions, so even if the heap runs out of space it can be possible to find memory for exceptions.
Hope this helps!
Nothrow was added to C++ primarily to support embedded systems developers that want to write exception free code. It is also useful if you actually want to handle memory errors locally as a better solution than malloc() followed by a placement new. And finally it is essential for those who wished to continue to use (what were then current) C++ programming styles based on checking for NULL. [I proposed this solution myself, one of the few things I proposed that didn't get downvoted :]
FYI: throwing an exception on out of memory is very design sensitive and hard to implement because if you, for example, were to throw a string, you might double fault because the string does heap allocation. Indeed, if you're out of memory because your heap crashed into the stack, you mightn't even be able to create a temporary! This particular case explains why the standard exceptions are fairly restricted. Also, if you're catching such an exception fairly locally, why you should catch by reference rather than by value (to avoid a possible copy causing a double fault).
Because of all this, nothrow provide a safer solution for critical applications.
Since dealing with Exceptions is heavier compared to a simple if(t), why isn't the normal new T() not considered less good practice, considering we will have to use try-catch() to check if a simple allocation succeeded (and if we don't, just watch the program die)?? What are the benefits (if any) of the normal new allocation compared to using a nothrow new? Exception's overhead in that case is insignificant ?
The penalty for using exceptions is indeed very heavy, but (in a decently tuned implementation) the penalty is only paid when an exception is thrown - so the mainline case stays very fast, and there is unlikely to be any measurable performance between the two in your example.
The advantage of exceptions is that your code is simpler: if allocating several objects you don't have to do "allocate A; if (A) { allocate B; if (B) etc...". The cleanup and termination - in both the exception and mainline case - is best handled automatically by RAII (whereas if you're checking manually you will also have to free manually, which makes it all too easy to leak memory).
Also, Assume that an allocation fails (eg. no memory exists in the system). Is there anything the program can do in that situation, or just fail gracefully. There is no way to find free memory on the heap, when all is reserved, is there?
There are many things that it can do, and the best thing to do will depend on the program being written. Failing and exiting (gracefully or otherwise) is certainly one option. Another is to reserve sufficient memory in advance, so that the program can carry on with its functions (perhaps with reduced functionality or performance). It may be able to free up some of its own memory (e.g. if it maintains caches that can be rebuilt when needed). Or (in the case of a server process), the server may refuse to process the current request (or refuse to accept new connections), but stay running so that clients don't drop their connections, and things can start working again once memory returns. Or in the case of an interactive/GUI application, it might display an error to the user and carry on (allowing them to fix the memory problem and try again - or at least save their work!).
Incase an allocation fails, and an std::bad_alloc is thrown, how can we assume that since there is not enough memory to allocate an object (Eg. a new int), there will be enough memory to store an exception ??
No, usually the standard libraries will ensure, usually by allocating a small amount of memory in advance, that there will be enough memory for an exception to be raised in the event that memory is exhausted.
Running out of memory is expected to be a rare event, so the overhead of throwing an exception when it happens isn't a problem. Implementations can "pre-allocate" any memory that's needed for throwing a std::bad_alloc
, to ensure that it's available even when the program has otherwise run out of memory.
The reason for throwing an exception by default, instead of returning null, is that it avoids the need for null checks after every allocation. Many programmers wouldn't bother doing that, and if the program were to continue with a null pointer after a failed allocation, it would probably just crash later with something like a segmentation fault, which doesn't indicate the real cause of the problem. The use of an exception means that if the OOM condition isn't handled, the program will immediately terminate with an error that actually indicates what went wrong, which makes debugging much easier.
It's also easier to write handling code for out-of-memory situations if they throw exceptions: instead of having to individually check the result of every allocation, you can put a catch
block somewhere high in the call stack to catch OOM conditions from many places throughout the program.
Going around exceptions because they're "too expensive" is premature optimisation. There is practically no overhead of a try/catch if an exception is not thrown.
Is there anything the program can do in that situation
Not usually. If there's no memory in the system, you probably can't even write anything to a log, or print to stdout, or anything. If you're out of memory, you're pretty much screwed.
In Symbian C++ it works the other way around. If you want an exception thrown when OOM you have to do
T* t = new(ELeave) T();
And you're right about the logic of throwing a new exception when OOM being strange. A scenario that is manageable suddenly becomes a program termination.