在C ++中,“throw”和“throw ex”之间有区别吗?

时间:2009-12-02 16:17:04

标签: c++ exception-handling

我想问this question(也是here),但这次是关于C ++。

之间C ++的区别是什么
try { /*some code here*/}
catch(MyException& ex)
{ throw ex;} //not just throw

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

它只是在堆栈跟踪中(在C ++中,在任何情况下都不是C#或Java中的标准)?

(如果有任何不同,我使用的是MSVS 2008.)

8 个答案:

答案 0 :(得分:32)

throw;重新抛出它在throw ex;抛出新异常时捕获的同一异常对象。除了创建新异常对象的性能原因之外,它没有什么区别。如果你有一个异常层次结构,其中有一些其他异常类派生自MyException类,并且在抛出异常时你已经完成throw DerivedClassException;它可以被catch(MyException&)捕获。现在,如果您修改此捕获的异常对象并使用throw;重新抛出它,则异常对象的类型仍为DerivedClassException。如果执行throw Ex;,则会发生对象切片,并且新抛出的异常将为MyException类型。

答案 1 :(得分:14)

  

[C++ FAQ Lite § 17.9] throw;throw关键字后面没有异常对象)是什么意思?我在哪里使用它?

     

您可能会看到类似这样的代码:

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

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

在此示例中,语句throw;表示“重新抛出当前异常”。这里,函数捕获异常(通过非const引用),修改异常(通过向其添加信息),然后重新抛出异常。这个习惯用法可以通过在程序的重要函数中添加适当的catch子句来实现一种简单的堆栈跟踪形式。

     

另一个重新抛出的习语是“例外调度员”:

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();
  }
}
     

这个习惯用法允许重复使用单个函数(handleException())来处理许多其他函数中的异常。

     

[C++ FAQ Lite § 17.11]当我抛出这个对象时,会被复制多少次?

     

取决于。可能是“零”。

     

抛出的对象必须具有可公开访问的复制构造函数。允许编译器生成任意次数复制抛出对象的代码,包括零。但是,即使编译器从未实际复制抛出的对象,它也必须确保异常类的复制构造函数存在且可访问。

编辑以更清楚地说明我认为很明显......

catch(MyException& ex) { throw ex; }可能会复制ex及其带来的所有问题; catch(MyException& ex) { throw; }可能不会。

答案 2 :(得分:12)

如果您有异常层次结构,throw ex可以对您的例外进行切片,而throw则不会。例如:

#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'
  } 
} 

throw ex更改为throw,您将获得derived的输出,这是您可能希望得到的。

答案 3 :(得分:5)

您可以将throw;表单与catch(...)一起使用(如果您使用了catch(...),这是重新抛出的唯一方法。)

答案 4 :(得分:3)

有很大的不同。我在我的博客上写了这篇文章:https://cpptalk.wordpress.com/2009/08/23/nuances-of-exception-rethrow/

非常欢迎您来看看

答案 5 :(得分:2)

throw ex将制作另一个副本,不建议仅使用throw来抛出当前的异常对象。

答案 6 :(得分:2)

throw可以抛出catch(...)捕获的非标准异常类型(例如结构化异常)

答案 7 :(得分:1)

此外,由于它有时会引起混淆,因此异常处理上下文之外的throw;将会中止该程序。