开发者

In C++, is there a difference between “throw” and “throw ex”?

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


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.


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


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.


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


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


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


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


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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜