Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

While I agree that catching ... without rethrowing is indeed wrong, I however believe that using constructs like this:

try
{
  // Stuff
}
catch (...)
{
  // Some cleanup
  throw;
}

Is acceptable in cases where RAII is not applicable. (Please, don't ask... not everybody in my company likes object-oriented programming and RAII is often seen as "useless school stuff"...)

My coworkers says that you should always know what exceptions are to be thrown and that you can always use constructs like:

try
{
  // Stuff
}
catch (exception_type1&)
{
  // Some cleanup
  throw;
}
catch (exception_type2&)
{
  // Some cleanup
  throw;
}
catch (exception_type3&)
{
  // Some cleanup
  throw;
}

Is there a well admited good practice regarding these situations?

share|improve this question

migrated from stackoverflow.com Dec 5 '11 at 22:00

This question came from our site for professional and enthusiast programmers.

3  
@Pubby: Not sure this is the exact same question. The linked question is more about "Should I catch ..." while my question focus on "Should I better catch ... or <specific exception> before rethrowing" –  ereOn Dec 5 '11 at 9:08
35  
Sorry to say that, but C++ without RAII is not C++. –  FredOverflow Dec 5 '11 at 9:24
28  
So your cow-workers dismiss the technique that was invented to deal with a certain problem and then quibble about which of the inferior alternatives should be used? Sorry to say, but that seems stupid, no matter which way I look at it. –  sbi Dec 5 '11 at 9:28
7  
"catching ... without rethrowing is indeed wrong" - you are mistaken. In main, catch(...) { return EXIT_FAILURE; } might well be right in code that isn't running under a debugger. If you don't catch, then the stack might not be unwound. It's only when your debugger detects uncaught exceptions that you want them to leave main. –  Steve Jessop Dec 5 '11 at 9:29
2  
... so even if it is a "programming error", it doesn't necessarily follow that you don't want to know about it. Anyway, your colleagues are not good software professionals, so as sbi says it's very difficult to talk about how best to deal with a situation that is chronically feeble to begin with. –  Steve Jessop Dec 5 '11 at 9:39

6 Answers 6

up vote 131 down vote accepted

My coworkers says that you should always know what exceptions are to be thrown [...]

Your coworker, I'd hate to say it, has obviously never worked on general-purpose libraries.

How in the world can a class like std::vector even pretend to know what the copy constructors will throw, while still guaranteeing exception safety?

If you always knew what the callee would do at compile-time, then polymorphism would be useless! Sometimes the entire goal is to abstract away what happens at a lower level, so you specifically don't want to know what's going on!

share|improve this answer
51  
+ for the uncensored truth –  Johannes Schaub - litb Dec 5 '11 at 9:08
20  
Actually, even if they knew that exceptions are to be thrown. What's the purpose of this code duplication? Unless the handling differs, I see no point in enumerating the exceptions to show off your knowledge. –  Michael Krelin - hacker Dec 5 '11 at 9:19
1  
@MichaelKrelin-hacker: That too. Also, add to it the fact that they deprecated exception specifications because listing all possible exceptions in the code tended to cause bugs later on... it's the worst idea ever. –  Mehrdad Dec 5 '11 at 9:21
3  
And what bothers me is what could be the origin of such an attitude when coupled with seeing useful and convenient technique as "useless school stuff". But well... –  Michael Krelin - hacker Dec 5 '11 at 9:24
1  
+1, the enumeration of all the possible options is an excellent recipe for a future failure, why on earth would someone chose doing that over ...? –  littleadv Dec 5 '11 at 9:32

Any answer of yes or no should be accompanied by a rationale of why this is so.

Saying that it is wrong simply because I've been taught that way is just blind fanaticism.

Writing the same //Some cleanup; throw several times, as in your example is wrong because is code duplication and that is a maintenance burden. Writing it just once is better.

Writing a catch(...) to silence all the exceptions is wrong because you should only handle exceptions you know how to handle, and with that wildcard you can cath more than you expect, and doing so can silence important errors.

But if you rethrow after a catch(...), then the latter rationale no longer applies, as you are not actually handling the exception, so there is no reason why this should be discouraged.

Actually I've been done this for logging in sensitive functions without any problem whatsoever:

void DoSomethingImportant()
{
    try
    {
        Log("Going to do something important");
        DoIt();
    }
    catch (std::exception &e)
    {
        Log("Error doing something important: %s", e.what());
        throw;
    }
    catch (...)
    {
        Log("Unexpected error doing something important");
        throw;
    }
    Log("Success doing something important");
}
share|improve this answer

I generally agree with the mood of the posts here, I really dislike the pattern of catching specific exceptions--I think that the syntax of this is still in it's infancy and not able to cope with the redundant code yet.

But since everyone is saying that, I'll pipe in with the fact that even though I use them sparingly I've often looked at one of my "catch(Exception e)" statements and said "Damn, I wish I'd called out the specific exceptions that time" because when you come in later it's often nice to know what the intention was and what the client is likely to throw at a glance.

I'm not justifying the attitude of "Always use x", just saying that occasionally it actually is nice to see them listed out and I'm sure that's why some people think it's the "Right" way to go.

share|improve this answer

What you seem to be caught in is the specific hell of someone trying to have their cake and eat it too.

RAII and exceptions are designed to go hand in hand. RAII is the means by which you do not have to write a lot of catch(...) statements to do cleanup. It will happen automatically, as a matter of course. And exceptions are the only way to work with RAII objects, because constructors can only succeed or throw (or put the object in an error state, but who wants that?).

A catch statement can do one of two things: handle an error or exceptional circumstance, or do cleanup work. Sometimes it does both, but every catch statement exists to do at least one of these.

catch(...) is incapable of doing proper exception handling. You don't know what the exception is; you can't get information about the exception. You have absolutely no information other than the fact that an exception was thrown by something within a certain code block. The only legitimate thing you can do in such a block is to do cleanup. And that means re-throwing the exception at the end of the cleanup.

What RAII gives you with regard to exception handling is free cleanup. If everything is RAII encapsulated properly, then everything will be properly cleaned up. You no longer need to have catch statements do cleanup. In which case, there is no reason to write a catch(...) statement.

So I would agree that catch(...) is indeed evil... provisionally.

That provision being proper use of RAII. Because without it, you need to be able to do certain cleanup. There's no getting around it; you have to be able to do cleanup work. You need to be able to ensure that throwing an exception will leave the code in a reasonable state. And catch(...) is a vital tool in doing so.

You cannot have one without the other. You cannot say that both RAII and catch(...) are bad. You need at least one of these; otherwise, you're not exception safe.

My coworkers says that you should always know what exceptions are to be thrown and that you can always use constructs like:

Your coworker is an idiot (or just terribly ignorant). This should be immediately obvious due to how much copy-and-paste code he's suggesting that you write. The cleanup for each of those catch statements will be exactly the same. That's a maintenance nightmare, not to mention readability.

In short: this is the problem that RAII was created to solve (not that it doesn't solve other problems).

What confuses me about this notion is that it's generally backwards to how most people argue that RAII is bad. Generally, the argument goes "RAII is bad because you have to use exceptions to signal constructor failure. But you can't throw exceptions, because it's not safe and you'll have to have lots of catch statements to clean everything up." Which is a broken argument because RAII solves the problem that the lack of RAII creates.

More than likely, he's against RAII because it hides details. Destructor calls aren't immediately visible on automatic variables. So you get code that gets called implicitly. Some programmers really hate that. Apparently, to the point where they think having 3 catch statements, all of which do the same thing with copy-and-paste code is a better idea.

share|improve this answer

I think your co-worker has mixed up some good advice - you should only handle known exceptions in a catch block when you don't re-throw them.

This means:

try
{
  // Stuff
}
catch (...)
{
  // General stuff
}

Is bad because it will silently hide any error.

However:

try
{
  // Stuff
}
catch (exception_type_we_can_handle&)
{
  // Deal with the known exception
}

Is fine - we know what we're dealing with and don't need to expose it to the calling code.

Likewise:

try
{
  // Stuff
}
catch (...)
{
  // Rollback transactions, log errors, etc
  throw;
}

Is fine, best practice even, the code to deal with general errors should be with the code that causes them. It's better than relying on the callee to know that a transaction needs rolling back or whatever.

share|improve this answer

Two comments, really. The first is that while in an ideal world, you should always know what exceptions might be thrown, in practice, if you're dealing with third party libraries, or compiling with a Microsoft compiler, you don't. More to the point, however; even if you do know exactly all of the possible exceptions, is that relevant here? catch (...) expresses the intent far better than catch ( std::exception const& ), even supposing that all possible exceptions derive from std::exception (which would be the case in an ideal world). As for using several catch blocks, if there is no common base for all exceptions: that is downright obfuscation, and a maintenance nightmare. How do you recognize that all of the behaviors are identical? And that that was the intent? And what happens if you have to change the behavior (bug fix, for example)? It's all too easy to miss one.

share|improve this answer
2  
Actually, my coworker designed his own exception class which does not derive from std::exception and tries everyday to enforce its use amongst our codebase. My guess is that he tries to punish me for using code and external libraries he has not written himself. –  ereOn Dec 5 '11 at 9:26
7  
@ereOn It sounds to me like your co-worker is in dire need of training. In any case, I'd probably avoid using libraries written by him. –  James Kanze Dec 5 '11 at 11:23
    
Templates and knowing what exceptions will be thrown go together like peanut butter and dead geckos. Something as simple as std::vector<> can throw any sort of exception for pretty much any reason. –  David Thornley Dec 6 '11 at 15:03
    
Please tell us, exactly how do you know what exception will be thrown by tomorrows bug fix further down the call tree? –  mattnz Sep 25 '12 at 4:03

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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