Which school of reporting function failures is better - c++

Very often you have a function, which for given arguments can't generate valid result or it can't perform some tasks. Apart from exceptions, which are not so commonly used in C/C++ world, there are basically two schools of reporting invalid results.
First approach mixes valid returns with a value which does not belong to codomain of a function (very often -1) and indicates an error
int foo(int arg) {
if (everything fine)
return some_value;
return -1; //on failure
}
The scond approach is to return a function status and pass the result within a reference
bool foo(int arg, int & result) {
if (everything fine) {
result = some_value;
return true;
}
return false; //on failure
}
Which way do you prefer and why. Does additional parameter in the second method bring notable performance overhead?

Don't ignore exceptions, for exceptional and unexpected errors.
However, just answering your points, the question is ultimately subjective. The key issue is to consider what will be easier for your consumers to work with, whilst quietly nudging them to remember to check error conditions. In my opinion, this is nearly always the "Return a status code, and put the value in a separate reference", but this is entirely one mans personal view. My arguments for doing this...
If you choose to return a mixed value, then you've overloaded the concept of return to mean "Either a useful value or an error code". Overloading a single semantic concept can lead to confusion as to the right thing to do with it.
You often cannot easily find values in the function's codomain to co-opt as error codes, and so need to mix and match the two styles of error reporting within a single API.
There's almost no chance that, if they forget to check the error status, they'll use an error code as if it were actually a useful result. One can return an error code, and stick some null like concept in the return reference that will explode easily when used. If one uses the error/value mixed return model, it's very easy to pass it into another function in which the error part of the co-domain is valid input (but meaningless in the context).
Arguments for returning the mixed error code/value model might be simplicity - no extra variables floating around, for one. But to me, the dangers are worse than the limited gains - one can easily forget to check the error codes. This is one argument for exceptions - you literally can't forget to handle them (your program will flame out if you don't).

boost optional is a brilliant technique. An example will assist.
Say you have a function that returns an double and you want to signify
an error when that cannot be calculated.
double divide(double a, double b){
return a / b;
}
what to do in the case where b is 0;
boost::optional<double> divide(double a, double b){
if ( b != 0){
return a / b;
}else{
return boost::none;
}
}
use it like below.
boost::optional<double> v = divide(a, b);
if(v){
// Note the dereference operator
cout << *v << endl;
}else{
cout << "divide by zero" << endl;
}

The idea of special return values completely falls apart when you start using templates. Consider:
template <typename T>
T f( const T & t ) {
if ( SomeFunc( t ) ) {
return t;
}
else { // error path
return ???; // what can we return?
}
}
There is no obvious special value we can return in this case, so throwing an exception is really the only way. Returning boolean types which must be checked and passing the really interesting values back by reference leads to an horrendous coding style..

Quite a few books, etc., strongly advise the second, so you're not mixing roles and forcing the return value to carry two entirely unrelated pieces of information.
While I sympathize with that notion, I find that the first typically works out better in practice. For one obvious point, in the first case you can chain the assignment to an arbitrary number of recipients, but in the second if you need/want to assign the result to more than one recipient, you have to do the call, then separately do a second assignment. I.e.,
account1.rate = account2.rate = current_rate();
vs.:
set_current_rate(account1.rate);
account2.rate = account1.rate;
or:
set_current_rate(account1.rate);
set_current_rate(account2.rate);
The proof of the pudding is in the eating thereof. Microsoft's COM functions (for one example) chose the latter form exclusively. IMO, it is due largely to this decision alone that essentially all code that uses the native COM API directly is ugly and nearly unreadable. The concepts involved aren't particularly difficult, but the style of the interface turns what should be simple code into an almost unreadable mess in virtually every case.
Exception handling is usually a better way to handle things than either one though. It has three specific effects, all of which are very good. First, it keeps the mainstream logic from being polluted with error handling, so the real intent of the code is much more clear. Second, it decouples error handling from error detection. Code that detects a problem is often in a poor position to handle that error very well. Third, unlike either form of returning an error, it is essentially impossible to simply ignore an exception being thrown. With return codes, there's a nearly constant temptation (to which programmers succumb all too often) to simply assume success, and make no attempt at even catching a problem -- especially since the programmer doesn't really know how to handle the error at that part of the code anyway, and is well aware that even if he catches it and returns an error code from his function, chances are good that it will be ignored anyway.

In C, one of the more common techniques I have seen is that a function returns zero on success, non-zero (typically an error code) on error. If the function needs to pass data back to the caller, it does so through a pointer passed as a function argument. This can also make functions that return multiple pieces of data back to the user more straightforward to use (vs. return some data through a return value and some through a pointer).
Another C technique I see is to return 0 on success and on error, -1 is returned and errno is set to indicate the error.
The techniques you presented each have pros and cons, so deciding which one is "best" will always be (at least partially) subjective. However, I can say this without reservations: the technique that is best is the technique that is consistent throughout your entire program. Using different styles of error reporting code in different parts of a program can quickly become a maintenance and debugging nightmare.

There shouldn't be much, if any, performance difference between the two. The choice depends on the particular use. You cannot use the first if there is no appropriate invalid value.
If using C++, there are many more possibilities than these two, including exceptions and using something like boost::optional as a return value.

C traditionally used the first approach of coding magic values in valid results - which is why you get fun stuff like strcmp() returning false (=0) on a match.
Newer safe versions of a lot of the standard library functions use the second approach - explicitly returning a status.
And no exceptions aren't an alternative here. Exceptions are for exceptional circumstances which the code might not be able to deal with - you don't raise an exception for a string not matching in strcmp()

It's not always possible, but regardless of which error reporting method you use, the best practice is to, whenever possible, design a function so that it does not have failure cases, and when that's not possible, minimize the possible error conditions. Some examples:
Instead of passing a filename deep down through many function calls, you could design your program so that the caller opens the file and passes the FILE * or file descriptor. This eliminates checks for "failed to open file" and report it to the caller at each step.
If there's an inexpensive way to check (or find an upper bound) for the amount of memory a function will need to allocate for the data structures it will build and return, provide a function to return that amount and have the caller allocate the memory. In some cases this may allow the caller to simply use the stack, greatly reducing memory fragmentation and avoiding locks in malloc.
When a function is performing a task for which your implementation may require large working space, ask if there's an alternate (possibly slower) algorithm with O(1) space requirements. If performance is non-critical, simply use the O(1) space algorithm. Otherwise, implement a fallback case to use it if allocation fails.
These are just a few ideas, but applying the same sort of principle all over can really reduce the number of error conditions you have to deal with and propagate up through multiple call levels.

For C++ I favour a templated solution that prevents the fugliness of out parameters and the fugliness of "magic numbers" in combined answers/return codes. I've expounded upon this while answering another question. Take a look.
For C, I find the fugly out parameters less offensive than fugly "magic numbers".

You missed a method: Returning a failure indication and requiring an additional call to get the details of the error.
There's a lot to be said for this.
Example:
int count;
if (!TryParse("12x3", &count))
DisplayError(GetLastError());
edit
This answer has generated quite a bit of controversy and downvoting. To be frank, I am entirely unconvinced by the dissenting arguments. Separating whether a call succeeded from why it failed has proven to be a really good idea. Combining the two forces you into the following pattern:
HKEY key;
long errcode = RegOpenKey(HKEY_CLASSES_ROOT, NULL, &key);
if (errcode != ERROR_SUCCESS)
return DisplayError(errcode);
Contrast this with:
HKEY key;
if (!RegOpenKey(HKEY_CLASSES_ROOT, NULL, &key))
return DisplayError(GetLastError());
(The GetLastError version is consistent with how the Windows API generally works, but the version that returns the code directly is how it actually works, due to the registry API not following that standard.)
In any case, I would suggest that the error-returning pattern makes it all too easy to forget about why the function failed, leading to code such as:
HKEY key;
if (RegOpenKey(HKEY_CLASSES_ROOT, NULL, &key) != ERROR_SUCCESS)
return DisplayGenericError();
edit
Looking at R.'s request, I've found a scenario where it can actually be satisfied.
For a general-purpose C-style API, such as the Windows SDK functions I've used in my examples, there is no non-global context for error codes to rest in. Instead, we have no good alternative to using a global TLV that can be checked after failure.
However, if we expand the topic to include methods on a class, the situation is different. It's perfectly reasonable, given a variable reg that is an instance of the RegistryKey class, for a call to reg.Open to return false, requiring us to then call reg.ErrorCode to retrieve the details.
I believe this satisfies R.'s request that the error code be part of a context, since the instance provides the context. If, instead of a RegistryKey instance, we called a static Open method on RegistryKeyHelper, then the retrieval of the error code on failure would likewise have to be static, which means it would have to be a TLV, albeit not an entirely global one. The class, as opposed to an instance, would be the context.
In both of these cases, object orientation provides a natural context for storing error codes. Having said that, if there is no natural context, I would still insist on a global, as opposed to trying to force the caller to pass in an output parameter or some other artificial context, or returning the error code directly.

I think there is no right answer to this. It depends on your needs, on the overall application design etc. I personally use the first approach though.

I think a good compiler would generate almost the same code, with the same speed. It's a personal preference. I would go on first.

If you have references and the bool type, you must be using C++. In which case, throw an exception. That's what they're for. For a general desktop environment, there's no reason to use error codes. I have seen arguments against exceptions in some environments, like dodgy language/process interop or tight embedded environment. Assuming neither of those, always, always throw an exception.

Well, the first one will compile either in C and C++, so to do portable code it's fine.
The second one, although it's more "human readable" you never know truthfully which value is the program returning, specifying it like in the first case gives you more control, that's what I think.

I prefer using return code for the type of error occured. This helps the caller of the API to take appropriate error handling steps.
Consider GLIB APIs which most often return the error code and the error message along with the boolean return value.
Thus when you get a negative return to a function call, you can check the context from the GError variable.
A failure in the second approach specified by you will not help the caller to take correct actions. Its different case when your documentation is very clear. But in other cases it will be a headache to find how to use the API call.

For a "try" function, where some "normal" type of failure is reasonably expected, how about accepting either a default return value or a pointer to a function which accepts certain parameters related to the failure and returns such a value of the expected type?

Apart from doing it the correct way, which of these two stupid ways do you prefer?
I prefer to use exceptions when I'm using C++ and need to throw an error, and in general, when I don't want to force all calling functions to detect and handle the error. I prefer to use stupid special values when there is only one possible error condition, and that condition means there is no way the caller can proceed, and every conceivable caller will be able to handle it.. which is rare. I prefer to use stupid out parameters when modifying old code and for some reason I can change the number of parameters but not change the return type or identify a special value or throw an exception, which so far has been never.
Does additional parameter in the
second method bring notable
performance overhead?
Yes! Additional parameters cause your 'puter to slow down by at least 0 nanoseconds. Best to use the "no-overhead" keyword on that parameter. It's a GCC extension __attribute__((no-overhead)), so YMMV.

Related

How to return an error from a function that returns signed integers

I have some psuedocode for a function to display a value and get a value
int getValue(){
int value;
// open file
// read line into "value"
if(error occurs){
// if file doesn't open or line was not an integer
/* Normally I would return something such as -1
but -1 in this case would be a valid value*/
value = ?
}
return value;
}
void displayValue(){
int value = getValue();
if(value is valid)
display(value);
}
As described in the code above, I would like to return that there was an error and let displayValue know that there was an error. But i want to accept negative,positive, and 0 from getValue.
Is there a better way to go about this? Does anyone have any advice?
Throw an exception. One of the advantages of C++ over C is that, when you have an error, you don't have to smuggle error codes out of the function, you can just throw an exception. If it's a truly exceptional case, most of the time the caller won't have anything useful to do with it anyway, so forcing them to check for it manually, then pass the error up the call chain is pointless. If they do know what to do with it, they can catch it.
This solution is also more composable. Imagine a scenario where A returns int, B calls A and returns a std::string based on it, and C calls B and returns class Foo based on that. If A has an exceptional condition that requires it to return an error, you can either:
Come up with some way to smuggle the error out of A as an int (or std::optional<int> or std::pair<bool, int> or whatever), then check for and convert that smuggled error to a different smuggled error for B, then check for and convert that to yet another smuggled error for C, then the caller of C still needs to check for that smuggled error and all three layers have to pay the price of the checks every time, even when all three layers succeeded, or...
You throw an exception in A, neither B nor C have anything useful to do with it (so they don't write any additional code at all), and the caller of C can choose to catch the exception and produce a friendlier error message if they so choose.
On modern architectures, the cost in the success case for #2 should be pretty negligible; the failure case might be more costly than the "check at every level case", but for something like "file doesn't exist" or "file contains corrupt data", it hardly matters if performance suffers, since you're probably about to exit the program (so speed doesn't count) or pop a dialog the user needs to respond to (the user is slower than the computer by many orders of magnitude).
There are several error handling approaches in C++:
The traditional way popular in C API's (also used by std::string algorithms) is to reserve at least one value as "invalid", which when returned would signal that there was an error, or that the value represents "no result". In case of error, the C API's would use the global errno to inform what error happened.
One of the features C++ introduced over the C language is exceptions. You can simply throw when error occurs. This is most appropriate for unexpected errors or pre/post-condition violations, rather than "no result exists" type situations.
Yet another way is to return both the value, and information about whether the result is valid. Old fashioned approach might be to return a pair of integer and boolean (or a named class that achieves the same). Alternatively, either value or error state can written into object passed through indirection. std::optional has been introduced into the standard library just for this kind of situation an is a great way of representing lack of result.
Latter approach can be further extended to not only return a boolean, but actual information about the error in similar way to the way exceptions do. The error information can also be wrapped with the value in a "variant" type so that they can share the space, as only one of them can exist at any time. This approach is similar to Maybe type in Haskell. There is a proposal to introduce a template for this purpose into the standard library.
Each of these approaches have their benefits and drawbacks. Choose one that is appropriate for your use case.
One option is to throw an exception when an error occurs. It's highly dependent on the rest of your project. Are Exceptions used all around ? Personally, I prefer more conventional old-school approaches. Mostly because people will start throwing exception everywhere, where it's not really exceptional and then it makes debugging much harder as the debugger keeps stopping for non-exceptional situations.
Another option is to return a pair std::pair<bool, int>. Some people love it, some people hate it.
My preference would be bool attemptGetValue(int& outValue). You return false if there's an error, in which case you don't touch outValue. Your return true otherwise and modify outValue
You can also use std::optional, but old timers might not be familiar wiht it.
Other than throwing an exception, returning a std::optional, or a std::pair, there is a precedent here: std::string::npos is normally set to a particularly large std::string::size_type value, normally -1 (wrapped around of course) and is used by some std::string functions to indicate a failure.
If you're willing to give up one legitimate return value then you could do something similar in your case. In reality though, typical (perhaps all) strings will be significantly smaller than npos; if that's not the case for you then perhaps one of the alternatives already mentioned would be better.

How to retrieve error from function?

Suppose I need to get value from config.
What function is more correctly?
int ret;
string value = config.getStringValue(string name, &ret);
or
string value;
int ret = config.getValue(string name, &value);
or maybe
string value = config.getStringValue(string name);
int ret = config.getResultCode();
And what var name for result code is more correctly: ret, error, etc?
Update:
Additional to #computerfreaker's comment: there is no exceptions in same platforms like bada
Neither solutions you proposed are the correct C++ way. What you provided is just C. In C++, use exceptions
The way you think is: "I have to send some status code to the caller"... this is the way you usually handle errors in C, but since there are exceptions in C++, it's much cleaner and wiser to do:
#include <exception>
std::string getValue() {
if (...)
throw std::exception("Unable to retrieve value.");
}
and caller would do:
try {
std::string val = getValue();
} catch (std::exception& e) { ... }
Just remember the rule: Throw by value, catch by reference.
Regarding "exceptions are meant for handling exceptional states" - it's true. Exceptions should be used in situations when something unexpected / exceptional happens. If function getValue relies on the fact that the value exists and it can be retrieved, then the situation when your code for some reason fails to retrieve this value is exceptional and thus suitable for handling it using exceptions.
C++ offers several ways of reporting errors from functions which return a value:
Throw an exception. This should be done when the cause of the error is with some external resource and does not normally happen. Perfect example: out of memory.
Return a special value to indicate failure, and follow this convention at the call site. For example, return "" for errors and have callers check for "".
Use std::optional or a similar technique. That's an advanced version of your first example. The basic idea is to return a special object which contains the original object and a boolean flag indicating success. The special object is used with the rule that the original object may only be accessed if the boolean flag indicates success. Other names of this idiom which I've heard are "Fallible" and "Box". This solution and the previous one are good candidates when error cases are expected and frequent -- usually a perfect match for user input.
Abort the program with assert. This is a good solution if an error indicates that your own code is wrong. In this case, the best thing to do is usually terminating the program as quickly as possible before it can do any harm.
Use global error state and have callers check it. That's your third example. C code fancies doing that a lot with errno. In C++, however, this is typically not considered a good solution. It's bad for the same reasons that any kind of global variable is typically bad.
Do not return the value itself but make it an out parameter with a reference. Return an error flag instead. That's your second example. It is better than the previous approach but still very C-like. I would not recommend doing it because it will force callers to name every received value.

Why use int functions over void?

I was looking over some example functions and methods (I'm currently in a C++ class), and I noticed that there were a few functions that, rather than being void, they were something like
int myFunction() {
// ...;
return 0;
}
Where the ellipses is obviously some other statement. Why are they returning zero? What's the point of returning a specific value every time you run a function?
I understand that main() has to be int (at least according to the standards) because it is related (or is?) the exit code and thus works with the operating system. However, I can't think of a reason a non-main function would do this.
Is there any particular reason why someone might want to do this, as opposed to simply making a void function?
If that's really what they're doing, returning 0 regardless of what the function does, then it's entirely pointless and they shouldn't be doing it.
In the C world, an int return type is a convention so that you can return your own "error code", but not only is this not idiomatic C++ but if, again, your programmer is always returning 0, then it's entirely silly.
Specifically:
I understand that main() has to be int (at least according to the standards) because it is related (or is?) the exit code and thus works with the operating system. However, I can't think of a reason a non-main function would do this.
I agree.
There's a common convention of int functions returning 0 for success and some non-zero error code for failure.
An int function that always returns 0 might as well be a void function if viewed in isolation. But depending on the context, there might be good reasons to make it compatible with other functions that returning meaningful results. It could mean that the function's return type won't have to be changed if it's later modified so it detects errors -- or it might be necessary for its declaration to be compatible with other int-returning functions, if it's used as a callback or template argument.
I suggest examining other similar functions in the library or program.
It's a convention, particularly among C programmers, to return 0 if the function did not experience any errors and return a nonzero value if there was an error.
This has carried over into C++, and although it's less common and less of a convention due to exception handling and other more object-oriented-friendly ways of handling errors, it does come up often enough.
One more issue that was not touched by other answers. Within the ellipses may be another return statement:
int myFunction() {
// ...;
if (error)
return code;
// ...;
return 0;
}
in which case myFunction is not always returning 0, but rather only when no error has occurred. Such return statements are often preferred over more structured but more verbose if/else code blocks, and may often be disguised within long, sloppy code.
Most of the time function like this should be returning void.
Another possibility is that this function is one of a series of closed-related functions that have the same signature. The return int value may signal the status, say returning 0 for success, and a few of these functions always succeed. To change the signature may break the consistency, or would make the function unusable as function objects since the signature does not match.
Is there any particular reason why someone might want to do this, as opposed to simply making a void function?
Why does your mother cut the ends off the roast before putting it in the oven? Answer: Because that's what her grandmother did. However, her grandmother did that for a simple reason: Her roast pan wasn't big enough to hold a full-sized roast.
I work with a simulation tool that in its earliest incarnations required that all functions callable by the simulation engine must return a success status: 0=success, non-zero=failure. Functions that could never fail were coded to always returned zero. The simulation engine has been able to accommodate functions that return void for a long, long, time. That returning an integer success code was the required behavior from some previous millennium hasn't stopped cargo cult programmers from carrying this behavior of writing functions that always returning zero forward to the current day.
In certain programming languages you find procedures and functions. In C, C++ and similar languages you don't. Rather you only have functions.
In practice, a procedure is a part of a program that performs a certain task. A function on the other hand is like a procedure but the function can return an answer back.
Since C++ has only functions, how would you create a procedure? That's when you would either create a void function or return any value you like to show that the task is complete. It doesn't have to be 0. You can even return a character if you like to.
Take for example, the cout statement. It just outputs something but not return anything. This works like a procedure.
Now consider a math function like tan(x). It is meant to use x and return an answer back to the program that called it. In this case, you cannot return just anything. You must return the value of the TAN operation.
So if you need to write your own functions, you must return a value based on what you're doing. If there's nothing to return, you may just write a void function or return a dummy value like 0 or anything else.
In practice though, it's common to find functions returning 0 to indicate that 'all went off well' but this is not necessarily a rule.
here's an example of a function I would write, which returns a value:
float Area ( int radius)
{
float Answer = 3.14159 * radius * radius;
return Answer;
}
This takes the radius as a parameter and returns the calculated answer (area). In this case you cannot just say return 0.
I hope this is clear.

C++ Best way to handle division by zero

I'm writing a C++ class that stores some double values in a vector (called mpValues) and calculates their average. When constructed, the value array is empty, so performing this calculation would return 0.0/0.0.
I decided that asking for the mean of zero values is a error. Therefore, it would be best to return NaN and display an error message, so that the user is made aware of that problem.
The code looks like this:
double Average::CalculateAverage() const
{
if(mpValues->size() == 0){
std::cerr << "Instance of Average at: " << this << " contains no values.\n"
<< "In this case the arithmetic mean is defined as NaN." <<std::endl;
return 0.0/0.0;
}
else{
...calculate the arithmetic mean
}
}
Is this a sensible approach, or do you have better suggestions? Usually, I wouldn't be so fussy, but this is a test for a job offer so I'd like to avoid bad decisions.
Thanks in advance!
The standard options are to return NaN, throw an exception, or return an option, such as boost::optional. There are advantages and disadvantages to each, which have been reviewed in detail by numerous people. Just do not display error messages within the function, since this violates the single responsibility principle.
You've already answered the question:
I decided that asking for the mean of zero values is an error.
Thus, there is no need to return NaN or handle zero division. You can create your own exception class (e.g. EmptyVectorError) and throw and catch it.
this is a C++ question, so we should give a C++ answer. From the single-responsibility principle (mentioned by Don Reba), we conclude that reporting an error from within your function is not really appropriate. There are two main options.
1 specify clearly that calling your average(container) with an empty container is undefined behaviour (UB). This is standard practice with many algorithms in the C++ std library. It allows you to ignore the possibility of an empty container and just return sum/size(). You may add assert(size()>0); (or similar) in debug mode.
2 explicitly allow for empty containers in the API (which I think is what you wanted to). In this case, returning sum/size() is inappropriate. It may return NaN or trigger a signal, depending on the error settings, but even a NaN is not easy to catch (I think isnan() is not a standard library function). So you must somehow return the undefined result in a clean way. This can be done by throwing an appropriate exception or by returning a type, such as boost::optional<> (suggested by usta), which explicitly allows for an undefined value that is not an error (unlike NaN with double).
I consider throwing an exception as the most appropriate way in C++ (if you go for option 2).
Change the return type to boost::optional<double>, I'd suggest.
Link to Doc
You have 2 options - either return NaN or throw an exception. What you should do, depends on the usage.
1) the client displays the mean only: then I would choose to simply return NaN. This way, the client is not forced to write error handling code for something he doesn't bother.
2) the client calculates new values using the mean: then it is difficult. By throwing an exception, you force him to handle it explicitly. This can be a good thing. On the other hand - the double value NaN can be used in calculations as far as I know. It also depends on the rest of your work. If you always use exceptions, you should use one as well. If you always use error codes, you should use NaN. If you mix - you should clean that up.
P.S.: I wouldn't write 0.0/0.0 but use std::numeric_limits instead. It's easier to read.

In C++ what are the benefits of using exceptions and try / catch instead of just returning an error code?

I've programmed C and C++ for a long time and so far I've never used exceptions and try / catch. What are the benefits of using that instead of just having functions return error codes?
Possibly an obvious point - a developer can ignore (or not be aware of) your return status and go on blissfully unaware that something failed.
An exception needs to be acknowledged in some way - it can't be silently ignored without actively putting something in place to do so.
The advantage of exceptions are two fold:
They can't be ignored. You must deal with them at some level, or they will terminate your program. With error code, you must explicitly check for them, or they are lost.
They can be ignored. If an error can't be dealt with at one level, it will automatically bubble up to the next level, where it can be. Error codes must be explicitly passed up until they reach the level where it can be dealt with.
The advantage is that you don't have to check the error code after each potentially failing call. In order for this to work though, you need to combine it with RAII classes so that everything gets automatically cleaned up as the stack unwinds.
With error messages:
int DoSomeThings()
{
int error = 0;
HandleA hA;
error = CreateAObject(&ha);
if (error)
goto cleanUpFailedA;
HandleB hB;
error = CreateBObjectWithA(hA, &hB);
if (error)
goto cleanUpFailedB;
HandleC hC;
error = CreateCObjectWithA(hB, &hC);
if (error)
goto cleanUpFailedC;
...
cleanUpFailedC:
DeleteCObject(hC);
cleanUpFailedB:
DeleteBObject(hB);
cleanUpFailedA:
DeleteAObject(hA);
return error;
}
With Exceptions and RAII
void DoSomeThings()
{
RAIIHandleA hA = CreateAObject();
RAIIHandleB hB = CreateBObjectWithA(hA);
RAIIHandleC hC = CreateCObjectWithB(hB);
...
}
struct RAIIHandleA
{
HandleA Handle;
RAIIHandleA(HandleA handle) : Handle(handle) {}
~RAIIHandleA() { DeleteAObject(Handle); }
}
...
On first glance, the RAII/Exceptions version seems longer, until you realize that the cleanup code needs to be written only once (and there are ways to simplify that). But the second version of DoSomeThings is much clearer and maintainable.
DO NOT try and use exceptions in C++ without the RAII idiom, as you will leak resources and memory. All your cleanup needs to be done in destructors of stack-allocated objects.
I realize there are other ways to do the error code handling, but they all end up looking somewhat the same. If you drop the gotos, you end up repeating clean up code.
One point for error codes, is that they make it obvious where things can fail, and how they can fail. In the above code, you write it with the assumption that things are not going to fail (but if they do, you'll be protected by the RAII wrappers). But you end up paying less heed to where things can go wrong.
Exception handling is useful because it makes it easy to separate the error handling code from the code written to handle the function of the program. This makes reading and writing the code easier.
return an error code when an error condition is expected in some cases
throw an exception when an error condition is not expected in any cases
in the former case the caller of the function must check the error code for the expected failure; in the latter case the exception can be handled by any caller up the stack (or the default handler) as is appropriate
Aside from the other things that were mentioned, you can't return an error code from a constructor. Destructors either, but you should avoid throwing an exception from a destructor too.
I wrote a blog entry about this (Exceptions make for Elegant Code), which was subsequently published in Overload. I actually wrote this in response to something Joel said on the StackOverflow podcast!
Anyway, I strongly believe that exceptions are preferable to error codes in most circumstances. I find it really painful to use functions that return error codes: you have to check the error code after each call, which can disrupt the flow of the calling code. It also means you can't use overloaded operators as there is no way to signal the error.
The pain of checking error codes means that people often neglect to do so, thus rendering them completely pointless: at least you have to explicitly ignore exceptions with a catch statement.
The use of destructors in C++ and disposers in .NET to ensure that resources are correctly freed in the presence of exceptions can also greatly simplify code. In order to get the same level of protection with error codes you either need lots of if statements, lots of duplicated cleanup code, or goto calls to a common block of cleanup at the end of a function. None of these options are pleasant.
Here's a good explanation of EAFP ("Easier to Ask for Forgiveness than Permission."), which I think applies here even if it's a Python page in Wikipedia. Using exceptions leads to a more natural style of coding, IMO -- and in the opinion of many others, too.
When I used to teach C++, our standard explanation was that they allowed you to avoid tangling sunny-day and rainy-day scenarios. In other words, you could write a function as if everything would work ok, and catch the exception in the end.
Without exceptions, you would have to get a return value from each call and ensure that it is still legitimate.
A related benefit, of course, is that you don't "waste" your return value on exceptions (and thus allow methods that should be void to be void), and can also return errors from constructors and destructors.
Google's C++ Style Guide has a great, thorough analysis of the pros and cons of exception use in C++ code. It also indicates some of the larger questions you should be asking; i.e. do I intend to distribute my code to others (who may have difficulty integrating with an exception-enabled code base)?
Sometimes you really have to use an exception in order to flag an exceptional case. For example, if something goes wrong in a constructor and you find it makes sense to notify the caller about this then you have no choice but to throw an exception.
Another example: Sometimes there is no value your function can return to denote an error; any value the function may return denotes success.
int divide(int a, int b)
{
if( b == 0 )
// then what? no integer can be used for an error flag!
else
return a / b;
}
The fact that you have to acknowledge exceptions is correct but this can also be implemented using error structs.
You could create a base error class that checks in its dtor whether a certain method ( e.g. IsOk ) has been called. If not, you could log something and then exit, or throw an exception, or raise an assert, etc...
Just calling the IsOk on the error object without reacting to it, would then be the equivalent of writing catch( ... ) {}
Both statement would display the same lack of programmer good will.
The transport of the error code up to the correct level is a greater concern. You would basically have to make almost all methods return an error code for the sole reason of propagation.
But then again, a function or method should always be annotated with the exceptions it can generate. So basically you have to same problem, without an interface to support it.
As #Martin pointed out throwing exceptions forces the programmer to handle the error. For example, not checking return codes is one of the biggest sources of security holes in C programs. Exceptions make sure that you handle the error (hopefully) and provide some kind of recover path for your program. And if you choose to ignore an exception rather than introduce a security hole your program crashes.