14

I was talking to a friend of mine that through my new code I didn't treat exceptions, just because I didn't know how to do it in C++. His answer surprised me: "why in the hell would you want to throw excetions?". I asked him why, but he didn't have a satisfying answer, so I googled it. One of the first pages I found was a blog entry, where the guy who posted wasn't totally against exceptions, but a religious war started in the replies: http://weblogs.asp.net/alex_papadimoulis/archive/2005/03/29/396141.aspx

Now I begin to wonder: is it that bad to throw an exception? For a student like I am, is it wrong to learn programming using exceptions as a normal thing? (When I throw exceptions, I catch them in another level of the code to treat them, most of the times). I have a code example, and I want to know what should I do:

int x;
cout << "Type an integer: ";
cin >> x;

Anything that is typed there that is not an integer will trigger an exception already, right? This exception should be treated there. But when I have a possible exception inside a class that is being used elsewhere in the program, should I make this method throw an exception so I can treat it wherever I call it or should I make it return a standard value when it has any problems?

The exception is always good, always bad, or something to be used in "exceptional" situations? Why?

9 Answers 9

17

The C++ iostreams classes do not, by default, use exception handling. Generally one should use exceptions for situations where an error can occur, but such errors are "unusual" and "infrequent" (such as a disk failing, the network being down, etc.). For error conditions that you do expect (such as the user providing invalid input), you should probably not use exception handling, unless the logic that needs to deal with this situation is far removed from the logic in which the situation is detected, in which case using an exception is the way to go. There is nothing wrong with using exceptions, and using exceptions where they are merited is definitely good... just avoid using them where if...else works just fine.

As to the why:

  1. Exceptions often provide a simple, elegant way of handling unexpected errors, but:
  2. Exception propagation, depending on the compiler and platform, may be slower than ordinary control flow, so if you can handle the situation locally, then that will be at least as fast... and you especially don't want to slow down the common, expected cases (such as invalid input). Also:
  3. Exceptions require more type information to be present and also require code that is unrelated to throwing or catching exceptions to be "exception-safe" which is why some object to exceptions.
11
  • 3
    +1 -- note that even if you do not use exceptions, you should probably be trying to write exception safe code, so that your code operates correctly when mixed with code that does use exceptions. Commented Aug 16, 2010 at 3:17
  • 3
    I'd add a #4: Exceptions can make it much harder to analyze program flow. This and the fact that exception usage is virulent (you can't just partially use them) is AFAIK the more common background for objections. Commented Aug 16, 2010 at 3:44
  • 2
    @George Fritzsche: Harder than what? If you are not using exceptions you need to use some other way to propagate error information back to some control point. If you use error codes (the most popular technique) the I would say that program flow is easier to analyze with exceptions than error codes. But yes exceptions is harder to analyze than zero error checking code but not quite as useful. Commented Aug 16, 2010 at 12:32
  • 1
    @Michael Aaron Safyan: In modern compilers when exceptions are not propagating the cost of exceptions handling code is unmeasurable (compared to other things like cache misses) and if used correctly (ie not used for control flow in normal code) the cost of throwing is not really relevant (as it is not normal control flow). Commented Aug 16, 2010 at 12:37
  • 1
    @Georg Fritzsche: I totally disagree. Yes error code is easy to follow within one function. But if you are trying to replace exceptions you have to intertwine error logic into functional code through multiple function calls. This leads to exceptionally (pun intended) hard to maintain code (which is why exceptions were introduced to avoid this exact situation). Exceptions allow program logic and error code to be separated thus reducing code complexity thus making it easier to maintain. Commented Aug 17, 2010 at 3:34
15

Question 1:

There is no reason not to use exceptions.
Whether to use exceptions or other techniques depends on the situation.

Exceptions are good to use when you can't fix the error locally.
(This should be an exceptional situation :-)

Error codes are good when you can fix the error locally.

Error codes are bad if you have a library that exposes an interface that returns an error code that needs to be manually checked. In the C world forgetting to check the error code was a significant source of problems.

Exceptions are good when you want to force the user of your interface to check for an error. If the user does not explicitly check and compensate; then the exception will propagate until either it is handled or the application exits.

Problems that come with exceptions:
If your code is a combination of C and C++. Functions with C ABI do not contain enough information for exceptions to propagate. Thus throwing an exception across a C function can (depending on the compiler and other factors) cause problems.

If you register a callback functions with a C library that uses C++ code. Then you must make sure that all exceptions are caught in the callback function and not allowed to propagate back to the C-library.

But this is true when combining any two languages. You can only use the most primitive features across language boundaries (and even that can take work if the languages do not align well). Therefore trying to use any advanced features is usually not supported.

Question 2:

C++ streams by default do not use exceptions.
This is because usually you want to handle the problem immediately.

In your example you use input as an example. In this situation you want to check the error and re-request the input.

int x;
cout << "Type an integer: "; 
cin >> x;
while(!cin)
{
    cin.clear();
    std::cout << "Failed: What do you think an integer is? Try again: ";
    cin >> x;
}

Note:

Personally I don't like the phrase 'Use exceptions in Exceptional circumstances". To me that is just to vague. vector::at() throws an exception. For me accessing off the end of an array is going to be exceptional (but for Joe student I doubt it will be exceptional (it will happen every second class as the lecturer throws a new curve ball at him/her)).

Thus I prefer the term "When the problem can not be fixed locally". A problem that can not be fixed locally is when something big has gone wrong (resource depletion (memory full throw bad_alloc()), coding error (access beyond array bounds (throw range_check()))) or any number of things that can not be fixed right there.

1

There is actually a legitimate reason behind why you shouldn't use exceptions.

The problem is when you throw exception across boundaries (e.g. from one DLL and try...catch it in another DLL) sometimes things can go very wrong. I got a slap on the wrist too when I used it in one of my projects.

Just google it you'll find all sorts of post on this topic, at least it was a problem few years ago when I was still a fulltime C++ developer :)

8
  • 3
    There's no standard way to do C++ anything across a DLL boundary. If you're writing a DLL, then it should have a C interface, not a C++ one. Commented Aug 16, 2010 at 3:02
  • @Billy ONeal: What kind of comment is that. It is pretty standard to have DLL with C++ objects only (no code just C++ classes and function with C++ linkage). What are you exactly referring to when you mean a C interface. Commented Aug 16, 2010 at 3:06
  • 3
    @Martin York: I mean if you write a C++ DLL, it will only be usable with the exact same compiler and compiler version as which created that DLL, because of things like differing name mangling schemes. If you truly want to produce a DLL, then the exported functions need to be C style, or you're chained to a particular compiler. -- Of course you're free to use C++ within the DLL itself. Commented Aug 16, 2010 at 3:10
  • 1
    @Martin York: And that's just one compiler: GCC has a completely different C++ ABI than MS's compiler, and you cannot use an executable produced by one with the other. (Though, for all I know, GCC has a command line switch to use the MS ABI) This was Billy ONeal's point: the two are incompatible. (And this isn't related to exceptions...) These are things you must take into account. Some projects, like Qt or wxWidgets use C++ DLLs anyways - you'll just have to distribute the right DLL, and keep it alongside your app.
    – Thanatos
    Commented Aug 16, 2010 at 3:39
  • 1
    @Martin York: I use GCC primarily on Windows. MS's compiler is not the only compiler in use, which gets back to ONeal's point. For example: If you want to compile native 64-bit apps on Windows, and don't want fork over the money, gcc is probably the best free compiler around. Whatever the reason, the original point is that C++ DLL ABI on Windows varies from compiler to compiler: something you must be aware of as a programmer. You cannot just pretend that MS is all there is and say "all the world is using the MS compiler"
    – Thanatos
    Commented Aug 16, 2010 at 4:13
1

I tend to follow this convention for internal parts of my applications code:

  • Do not throw exceptions of your own.
  • Catch any exception that could be expected from your calls to other code inmediately. Treat it accordingly, for example returning an error code, or "false" with the meaning of no success.

However when designing components, I do use component-scope exceptions, like for example, if connecting to a required database (one which is set up by the installer) fails. Or when you try to call any method violating its preconditions. In general, preconditions are expressed with assertions; however, in the public layer of your component, they should be checked and an exception thrown if they are violated, otherwise the caller has a hard job finding what they are doing wrong. (An alternative is of course to use a debug version, in which failed assertions will scream at you; but this is not always practical - distributing two binaries, keeping them up to date, etc.)

In my opinion, the only general rule is to be consistent and write correct code - choose some way to handle the erroneous/exceptional situations, and follow it consistently.

0

I think exception handling/throwing can be boiled down to the following:

  • Use RAII (or using in C#, or with in Python) so your code is exception safe.
  • Catch exceptions if there's a chance to recover from the error, else let them bubble up.
  • Throw exception only if you have something useful to add.

Consider a hypothetical example where you're using a serial port communication library to communicate with an external sensor of sorts. Furthermore:

  • The serial port communication library reports errors by throwing exceptions.
  • The sensor itself can communicate certain error messages through status codes in cases when it's no longer able to acquire data, when it's functioning outside its max/min operating conditions, etc.
  • You're using RAII (Resource Acquisition Is Initialization), so if the serial port library throws an exception you wouldn't have to worry about releasing any acquired resources.

If the serial port library thrown an exception, you can:

  1. Catch the exception and try to recover from it somehow, e.g. by reinitializing the library.
  2. Catch the exception, wrap it in your own, and then throw the new exception up the call stack.

Option #1 is unlikely in most cases. And option #2 would probably not add any valuable information to what's already in the original exception.

So usually it's best to allow original exception to bubble up (this is again assuming the RAII is in place and no clean up is needed).

On the other hand, if the sensor itself reports an error code, then it makes a lot of sense to throw your own exception.

0
0

This one is also a very interesting and controversial reading on the argument:

http://blogs.msdn.com/b/oldnewthing/archive/2005/01/14/352949.aspx

0

Throw an exception if, and only if, the alternative is failure to meet a post condition or to maintain an invariant.

That advice replaces an unclear subjective decision (is it a good idea) with a technical, precise question based on design decisions (invariant and post conditions) you should already have made.

-1

If you just blindly go and say I won't use exceptions it means you're not going to use most of the STL. That means you need to write your own classes for strings/vector etc etc ...

Plus exceptions are a much cleaner way of doing error handling (IMHO) and if you already do RAII then adding exceptions is not much harder.

-3

Read everything in Section 14 upto section 14.2 of Bjarne Stroustrup: "C++ programming Language Third Edition"

It is the most convincing answer I have come across.

Not the answer you're looking for? Browse other questions tagged or ask your own question.