Reputation: 702
I'm somewhat confused when talking about error handling. Take Direct2D for example. Before we can start using Direct2D functionality, we have to create a ID2DFactory object:
HRESULT hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &d2d1Factory);
As you can see from above. We can check the HRESULT hr to see if we have successfully created the ID2DFactory. I think when this calling fails, even if I call it again, it still fails. We don't have any method to recover from this failure.
So what's the point of checking the return value? Is it so that we can tell the user what's going wrong before terminating the program?
Another example is out-of-memory. When we come across the rare occasion that we don't have enough memory for our program to "new" some objects. In C++, when run out of memory, new operator may return NULL or raise an error. If you don't test whether it is NULL nor catch the error, your program terminates. I don't think your program can recover from this circumstance.
So again, what's the point of checking if there's a severe error which you can do nothing about it?
Upvotes: 1
Views: 399
Reputation: 187
Initialization functions like your D2D1CreateFactory() can fail. Such a failure generally means the O/S on your PC is completely hosed and you need to reboot. This information is valuable to the user, who would like to know "O/S is hosed, reboot and try again" versus "dereferenced nil at like 2345 in module mod.c". If you don't catch error conditions, all you user knows is the program crashed.
Capturing error returns and exceptions, and reporting them to the user is one of the many things that separates a good program from a poor one.
In particular with new, your program often has many options. It may be able to re-request a smaller initial block of memory. It may be able to return memory holding cached values and try again. It may be able to save files in preparation for exiting, which also has the effect of returning memory.
When you handle an error return or exception, you have four choices; abort, alternate, retry, fail.
To abort is to clean up and exit; preferrably returning resources, closing files, and saving work-in-process.
To alternate is to try a whole different method of doing the same thing; like trying ftp if you can't use http. Alternating is the hardest error recovery method, and frankly mostly only NASA has the budget to code this kind of error handling.
To retry is to simply attempt the same operation again. If the failure is transient, this may be successful. If the failure is persistent, retry can lead to an infinite loop, so retry is best done with a limit counter or exponentially increasing time delay.
To fail is to simply drop the request or action and attempt to process the next request. Fail may seem silly because it means a request was not performed, a screen was not updated, or user input was ignored. But surprisingly often, the user can recover from such an error by doing something external to the program, or by trying again when circumstances are different. It turns out in most cases that if the program terminates, it completely denies service to the user, who might be able to work with a damaged or partially correct program. (Try to imagine a flight control system aborting just because it dereferenced nil. This is not what you want.)
Upvotes: 1
Reputation: 67233
Image two programs that each encounter an error.
One crashes due to insufficient memory or whatever, causing an illegal use of memory and the operating system either displays some obscure error or just silently shuts the program down.
The other application displays a simpler error message and then rolls back the operation that caused the error so that you can decided if you want to continue and/or try and resolve the condition that is causing the error. (For example, maybe closing some other applications will allow there to be more memory.)
Which program would you rather use?
Upvotes: 0
Reputation: 146940
Checking return values and such is always critical for debugging. Just use a macro for it.
Upvotes: 0
Reputation: 11232
There may be so many things to cleanup like opened file handles, or some database operation to rollback etc which needs to be performed in case of error. And in some cases, error might not be critical and it may be possible for the program to continue with only partial functionality available instead of crashing altogether. Last but not the least, it provides valuable information regarding where error occurred which is invaluable for debugging.
BTW, unless you are using some ancient compiler which is non-conformant, new
can not return NULL as per C++ standard, it has to throw std::bad_alloc
exception in case of failure.
Upvotes: 0
Reputation: 91270
Ever had a bug report from a customer saying "it just crashed"? They're much more useful when the bug report includes a screenshot of your error dialog saying "D2D1CreateFactory returned E_...".
Upvotes: 2
Reputation: 35594
First of all, not every error in irrecoverable. Example: if the file user wants to open is not available, the program may want to report this to the user and ask for another file to open.
Second, even if the program cannot continue, it must have a chance to terminate gracefully, informing the user about the problem, saving the state, logging the problem for the future analysis etc., and not just crash. Without the error checking, the program would most probably crash.
Upvotes: 4