views:

571

answers:

8

I'd like to ask this question (also here), but this time about C++.

What is the difference in C++ between

try { /*some code here*/}
catch(MyException& ex)
{ throw ex;}

and

try {  /*some code here*/}
catch(MyException& ex)
{ throw;}

Is it just in the stack trace (which in C++ is in any case not a standard as in C# or Java)?

(If it makes any difference, I use MSVS 2008.)

+2  A: 

throw ex will make another copy and is not recommend use throw only to throw the current exception object.

Priyank Bolia
That's true, but only if you catch by value - which is not the recommended way anyway
Phil Nash
As in the code sample, I am doing catch-by-reference, so that should not be an issue.
Joshua Fox
Hm, a test shows that indeed a copy is made (even if you catch by reference), and slicing happens in the process. Simple **throw** rethrows the exception without slicing, even if the real exception type is a derived class of `MyException`.
UncleBens
@UncleBens - as I conceded elsewhere, you are right on this. That is surprising
Phil Nash
+5  A: 

You can use the throw; form with catch(...) (that is it is the only way to rethrow if you caught using catch(...) ).

Phil Nash
The two have nothing in particular to do with each other. `throw` means to throw the currently processed exception, and `catch(...)` means to catch any exception.
David Thornley
My point was that if you caught using catch(...) you cannot rethrow any other way. In the example where an exception is caught by reference, and not modified, there is no real distinction.
Phil Nash
updated to reflect that
Phil Nash
Yes, but I'm really wondering -- given code as in the sample, where I can choose either one, which should I choose, and why?
Joshua Fox
If you just want to rethrow the original exception, use throw;
Phil Nash
The edit makes things much clearer, so I've changed my vote.
David Thornley
+11  A: 
ephemient
Sure, but given that I can choose, in the code above, to do one or the other, what is the difference?
Joshua Fox
Great answer, I'll add the comment that we've seen a speed up in our code by moving a large block of exception catching into it's own function. The speed up was due to making the functions smaller by putting the catch blocks into a function.
chollida
I'd never noticed that "exception dispatcher" idiom before. Interesting.
Greg D
+2  A: 

throw can throw a nonstandard exception type that was caught by catch(...) (eg structured exception)

Joshua
Wasn't that documented as "unintended side effect in VC6, fixed in VC7"?
peterchen
Yes, that is a good point. In this case, though, I know the exception type (MyException). So, is there a difference?
Joshua Fox
@peterchen, I hope not. That was darn useful to catch SEH exceptions, clean up, and rethrow them.
Joshua
+16  A: 

throw; rethrows the same exception object it caught while throw ex; throws a new exception. It does a make difference other than the performance reasons of creating a new exception object. If you have a exception hierarchy where there some other exception classes derived from MyException class and while throwing an exception you have done a throw DerivedClassException; it can be caught by the catch(MyException&). Now if you modify this caught exception object and rethrow it using throw; the type of exception object will still be DerivedClassException. If you do throw Ex; the object slicing occurs and the newly thrown exception will be of type MyException.

Naveen
that depends what ex is. In the example it will be the same object as it is caught by reference (which is the standard way)
Phil Nash
@Naveen, object slicing will not occur if you have caught by reference. If you caught by value the slicing would already have occured although at that point `throw;` would save you because it rethrows the original exception)
Phil Nash
@Phil: You are right, I'll edit the answer.
Naveen
@Phil: This raises an interesting question. GCC slices even when catching by reference... I wonder what the standard says.
Managu
@Phil: no, read 15.1/3 and 15.1/6. Even if `ex` is a reference, `throw ex;` doesn't (necessarily) throw the referand, it initializes a temporary object using the referand. The temporary may or may not be elided. `throw;`, on the other hand, is specified to re-use the existing temporary.
Steve Jessop
@Steve: Suppose it were catch (exception *ex) {throw ex;}, and this was caught by another catch (exception *ex). As only pointers are represented, one expects no slicing (as the temporary objects would just be temporary pointers). How is it different with references?
Managu
@Steve, @Managu. Actually you are right. I didn't realise that. That is surprising. I retract my earlier comments
Phil Nash
@Phil: Checked More Effective C++ Item 12, object slicing does occur. Rolled back my answer to the original answer.
Naveen
@Managu - throwing/ catching by pointer does work as expected. The difference is that the value of a pointer is the address, but the value of a reference is what it references (even if it's implemented by pointers under the hood)
Phil Nash
@Phil: thanks, that's roughly what I was going to say, but I went and wrote some code to prove it to myself first :-). The difference is that there's such a thing as a pointer object, but no such thing as a reference object. So the temporary intialised by a throw expression can be a pointer, but can't be a reference.
Steve Jessop
Dagnammit! I just finger fumbled, and accidentally downvoted this answer. And I can't undo it, I'm being told "vote is too old to change unless the answer is edited". So I edited the answer to add the missing full stop at the end, just so I could vote it back up again. Sorry, Naveen.
Steve Jessop
+1 For warning about slicing.Exceptions are always thrown by value so you need to know their exact type at compile time when you use throw.
Tomek Szpakowicz
+8  A: 

If you have an exception hierarchy, throw ex can slice your exception, while throw won't. For example:

#include <iostream> 
#include <string> 

using namespace std; 

struct base 
{ 
  virtual string who() {return "base";} 
}; 

struct derived : public base 
{ 
  string who() {return "derived";} 
}; 

int main() { 
  try { 
    try { 
      throw derived(); // throws a 'derived'
    }  
    catch (base& ex)  
    { 
      throw ex; // slices 'derived' object to be a 'base' object
    } 
  } 
  catch (base& ex) 
  { 
    cout<<ex.who()<<endl; // prints 'base'
  } 
}

Change throw ex to just throw, and you'll get an output of derived, which is what you probably expected to get.

Managu
+1 for mentioning slicing
peterchen
Thanks. That's surprising. I wouldn't think that slicing can occur in handling an object by reference.
Joshua Fox
A: 

Additionally, since it sometimes causes confusion, a bare throw; outside of an exception-handling context will abort the program.

Adam
Any throw that isn't caught will call `unexpected()`, which will call `terminate()` unless otherwise specified (names from memory). What's the difference between a bare `throw` and a `throw something` in that case?
David Thornley
@David, i think Adam means a "throw;" while a handler is not being active. That is, outside of any dynamic exception-handler scope it will call std::terminate (it does not need to occur inside the braces of an exception handler, but such an handler has to have been entered before and not left in the current execution sequence).
Johannes Schaub - litb
+2  A: 

There's a big difference. I wrote about it on my blog, at: http://cplusplus.co.il/2009/08/23/nuances-of-exception-rethrow/

You are more than welcome to have a look

rmn