Exceptions, from a higher view

OK... Can someone justify common exception usage?

I have come into programming from mathematics for almost a year now and feel like I am hitting my stride. I am feeling comfortable with c++ - what I do not know I can look up and it makes sense... except for many uses of exceptions!

On the one hand exceptions are obvious and important - you have to deal with issues arising from the system that you are using (or from third party libraries). Deal with that Bad_Alloc! There exist intelligent procedures to write code on this basis (do anything that might throw, then change, etc).

On the other hand, from what I have seen in example code, the overwhelming use of exceptions seem to be an excuse not to write tight code. Does anyone really need an exception to check that the passed variable fits a range? Why?

PS That is a serious question - am I missing something here?
Last edited on
When used properly (which admittedly is often difficult), exceptions let you write code that isn't riddled with a bunch of error checking. Rather than checking the result of every single operation to see whether or not it failed, you can just write your code assuming it all worked OK, and then write a seperate block of code that's jumped to if there was a problem anywhere along the line.


For example...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 // assuming these "DoXXX" functions throw exceptions

try
{
  DoSomeStuff();

  DoMore();

  DoEvenMore();
}
catch(std::exception& e)
{
  // something failed somewhere
  Cleanup();
  AlertUser(e->what());
}


This is convenient because:
- all the error code is written once (no duplicate code)
- the error logic is separated from the main logic, making the main logic easier to follow


The common alternative is for functions to return an "error code" to indicate they failed instead of throwing an exception. This causes you do constantly be checking for failures and have error handling code slapped all over the place, making the main logic much more confusing and adding all sorts of duplicate code.

Here's an example of how that might look:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 // assuming these "DoXXX" functions return error codes instead of throwing exceptions

int code = DoSomeStuff();
if(code != Success)
{
  Cleanup();
  AlertUser( GetErrorString( code ) );
  return;
}

code = DoMore();
if(code != Success)
{
  Cleanup();
  AlertUser( GetErrorString( code ) );
  return;
}

code = DoEvenMore();
if(code != Succes)
{
  Cleanup();
  AlertUser( GetErrorString( code ) );
  return;
}


As you can see this is quite a bit messier.


Does anyone really need an exception to check that the passed variable fits a range? Why?


If an out of range variable is used as an array index, that could be big problems. Stepping out of bounds in an array is one of the most common ways to get heap corruption, the worst kind of program bug.
Last edited on
The passed variable was more of an iconic example than a real question.

What you say makes sense, except that it leads to everything being handled at the client end of the function. Wouldn't it be better to call functions DoSomeStuff etc that take care of their own potential problems and return in order (or with an error message that says: tried but failed, no need to clean up.)?
DoSomeStuff would clean up whatever it needs to clean up, yes. But it can't possibly clean up what the client would need to clean up in the event of a failure.

(Note that cleanup isn't always applicable, especially if you practice RAII techniques)

Say for example you allocate some memory that you pass to DoSomeStuff:

1
2
3
int* foo = new int[100];

DoSomeStuff(foo);


Now if DoSomeStuff fails, you'd need to delete[] that memory. There's no way DoSomeStuff can delete it itself (or at least, it shouldn't because there's no guarantee it was allocated that way).

Furthermore, if DoSomeStuff fails, you wouldn't want DoMore() or DoEvenMore() to be run because the overall process already failed. So either way, the client needs to be aware of the errors somehow.
Last edited on
Right - that makes perfect sense.

But it does use a c style array. What if you have some means in place for keeping track of your created objects (from, in this case, a vector, to, say an information object stocked with pointers that will be kept in the appropriate state on error returns)?

(PS this is a sort of work out why I am wrong exercise - I do not think I am cleverer that the programming community, but I do want to know exactly why I am dumber!)
Exceptions should be thrown when all of the following are true:
1) The function itself cannot meet its post-conditions
2) In typical usage, it is not the immediate caller that handles the cleanup

The reason for #2 is that if the immediate caller always handles the error, then the extra syntactic baggage
makes the code less clear than simply returning an error code. RAII is necessary to avoid each function
from having to have a catch() block and perform explicit cleanup.

Exceptions should also be thrown when returning an error is not an option. For example,
constructors cannot return error codes, nor can operators. The one exception(!) to this
rule is destructors: destructors should never leak an exception.
Thanks jsmith (and disch)

So it sounds like this is useful primarily when you, as designer, know that the immediate caller will often not be the one to handle the error, and do not what (potentially) complicated error handling passed manually up through the stack.

Would this be a fair summary?

And would you as a programmer say that the use of exceptions in this way (as opposed to handling actual system problems) is useful?

This seems to be taught in the books as an obvious slam dunk, but I have not felt a great compulsion to do it this way (possibly its advantages are evident on use?). Partly because it is not always clear at write-time who the user will be.
Last edited on
Yes. and yes.

Exceptions have their useful place in the language. And so do simple return codes. The trick is knowing
when to use each.
Hmmm. What is the trick...
What I said above, which is mostly what Sutter and Alexandrescu say in C++ Coding Standards.

Though some will also say that exceptions should be used only for exceptional cases.
Topic archived. No new replies allowed.