23

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;} //not just throw

and

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

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.)

Community
  • 1
  • 1
Joshua Fox
  • 18,704
  • 23
  • 87
  • 147

8 Answers8

38

throw; rethrows the same exception object it caught while throw ex; throws a new exception. It does not make a 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.

Joshua Fox
  • 18,704
  • 23
  • 87
  • 147
Naveen
  • 74,600
  • 47
  • 176
  • 233
  • 3
    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) – philsquared Dec 02 '09 at 16:31
  • 2
    @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) – philsquared Dec 02 '09 at 16:35
  • @Phil: This raises an interesting question. GCC slices even when catching by reference... I wonder what the standard says. – Managu Dec 02 '09 at 16:39
  • 3
    @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 Dec 02 '09 at 16:42
  • @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 Dec 02 '09 at 16:47
  • @Steve, @Managu. Actually you are right. I didn't realise that. That is surprising. I retract my earlier comments – philsquared Dec 02 '09 at 16:49
  • 2
    @Phil: Checked More Effective C++ Item 12, object slicing does occur. Rolled back my answer to the original answer. – Naveen Dec 02 '09 at 16:50
  • 1
    @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) – philsquared Dec 02 '09 at 16:51
  • 1
    @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 Dec 02 '09 at 17:05
  • 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 Dec 02 '09 at 17:20
  • +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 Dec 02 '09 at 17:54
  • The second sentence of this answer says "It does not make a difference other than the performance...", then the rest of the answer proceeds to explain how it does make a difference. – Jeffrey Bosboom Dec 08 '16 at 01:57
14

[C++ FAQ Lite § 17.9] What does throw; (without an exception object after the throw keyword) mean? Where would I use it?

You might see code that looks something like this:

class MyException {
public:
  ...
  void addInfo(const std::string& info);
  ...
};

void f()
{
  try {
    ...
  }
  catch (MyException& e) {
    e.addInfo("f() failed");
    throw;
  }
}

In this example, the statement throw; means "re-throw the current exception." Here, a function caught an exception (by non-const reference), modified the exception (by adding information to it), and then re-threw the exception. This idiom can be used to implement a simple form of stack-trace, by adding appropriate catch clauses in the important functions of your program.

Another re-throwing idiom is the "exception dispatcher":

void handleException()
{
  try {
    throw;
  }
  catch (MyException& e) {
    ...code to handle MyException...
  }
  catch (YourException& e) {
    ...code to handle YourException...
  }
}

void f()
{
  try {
    ...something that might throw...
  }
  catch (...) {
    handleException();
  }
}

This idiom allows a single function (handleException()) to be re-used to handle exceptions in a number of other functions.

[C++ FAQ Lite § 17.11] When I throw this object, how many times will it be copied?

Depends. Might be "zero."

Objects that are thrown must have a publicly accessible copy-constructor. The compiler is allowed to generate code that copies the thrown object any number of times, including zero. However even if the compiler never actually copies the thrown object, it must make sure the exception class's copy constructor exists and is accessible.

(edited for more clarity on what I thought was obvious...)

catch(MyException& ex) { throw ex; } may copy ex, with all the issues that it entails; catch(MyException& ex) { throw; } may not.

ephemient
  • 198,619
  • 38
  • 280
  • 391
  • Sure, but given that I can choose, in the code above, to do one or the other, what is the difference? – Joshua Fox Dec 02 '09 at 16:40
  • 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 Dec 02 '09 at 16:41
  • I'd never noticed that "exception dispatcher" idiom before. Interesting. – Greg D Dec 02 '09 at 17:18
13

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
  • 8,849
  • 2
  • 30
  • 36
6

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

philsquared
  • 22,403
  • 12
  • 69
  • 98
  • 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 Dec 02 '09 at 16:36
  • 1
    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. – philsquared Dec 02 '09 at 16:37
  • 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 Dec 02 '09 at 16:41
  • If you just want to rethrow the original exception, use throw; – philsquared Dec 02 '09 at 16:57
3

There's a big difference. I wrote about it on my blog, at: https://cpptalk.wordpress.com/2009/08/23/nuances-of-exception-rethrow/

You are more than welcome to have a look

Will_of_fire
  • 1,089
  • 4
  • 12
  • 24
rmn
  • 2,386
  • 1
  • 14
  • 21
2

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

Priyank Bolia
  • 14,077
  • 14
  • 61
  • 82
  • 1
    That's true, but only if you catch by value - which is not the recommended way anyway – philsquared Dec 02 '09 at 16:22
  • As in the code sample, I am doing catch-by-reference, so that should not be an issue. – Joshua Fox Dec 02 '09 at 16:23
  • 4
    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 Dec 02 '09 at 16:34
  • @UncleBens - as I conceded elsewhere, you are right on this. That is surprising – philsquared Dec 02 '09 at 16:52
2

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

Joshua
  • 40,822
  • 8
  • 72
  • 132
1

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

Adam
  • 406
  • 3
  • 9
  • 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 Dec 02 '09 at 17:59
  • @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 Dec 02 '09 at 18:04