【问题标题】:In C++, is there a difference between “throw” and “throw ex”?在 C++ 中,“throw”和“throw ex”有区别吗?
【发布时间】:2010-12-22 11:35:16
【问题描述】:

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

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

【问题讨论】:

  • throw ex; // out of apartment
  • @sehe 我的错,我完全没有抓住重点。

标签: c++ exception-handling


【解决方案1】:

throw ex 会创建另一个副本,不建议使用throw 仅用于抛出当前异常对象。

【讨论】:

  • 确实如此,但前提是您按价值捕获 - 无论如何这不是推荐的方式
  • 在代码示例中,我正在执行 catch-by-reference,所以这应该不是问题。
  • 嗯,测试表明确实复制了一份(即使您通过引用捕获),并且在此过程中会发生切片。简单 throw 重新抛出异常而不进行切片,即使真正的异常类型是 MyException 的派生类。
  • @UncleBens - 正如我在其他地方承认的那样,你是对的。这很令人惊讶
【解决方案2】:

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

【讨论】:

  • 两者没有什么特别的关系。 throw 表示抛出当前处理的异常,catch(...) 表示捕获任何异常。
  • 我的意思是,如果您使用 catch(...) 捕获,则无法以任何其他方式重新抛出。在通过引用捕获异常且未修改的示例中,没有真正的区别。
  • 是的,但我真的很想知道——给定示例中的代码,我可以在哪里选择其中一个,我应该选择哪个,为什么?
  • 如果只想重新抛出原来的异常,使用 throw;
【解决方案3】:

[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; 表示“重新抛出当前异常”。在这里,一个函数捕获了一个异常(通过非常量引用),修改了异常(通过向其添加信息),然后重新抛出异常。通过在程序的重要函数中添加适当的 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; } 可能不会。

【讨论】:

  • 当然可以,但是鉴于我可以在上面的代码中选择做一个或另一个,有什么区别?
  • 很好的答案,我将添加注释,通过将一大块异常捕获移动到它自己的函数中,我们已经在代码中看到了加速。加速是由于通过将 catch 块放入函数来使函数更小。
  • 我以前从未注意到“异常调度程序”这个成语。很有趣。
【解决方案4】:

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

【讨论】:

  • 这不是记录为“VC6 中的意外副作用,在 VC7 中修复”吗?
  • 是的,这很好。不过,在这种情况下,我知道异常类型 (MyException)。那么,有区别吗?
  • @peterchen,我希望不会。这对于捕获 SEH 异常、清理并重新抛出它们非常有用。
【解决方案5】:

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

【讨论】:

  • 这取决于 ex 是什么。在示例中,它将与通过引用捕获的对象相同(这是标准方式)
  • @Naveen,如果您通过引用捕获,则不会发生对象切片。如果您按值捕获,则切片将已经发生,尽管此时 throw; 会节省您,因为它会重新抛出原始异常)
  • @Phil:不,请阅读 15.1/3 和 15.1/6。即使ex 是一个引用,throw ex; 也不会(必然)抛出引用,它使用引用初始化一个临时对象。临时的可能会或可能不会被省略。另一方面,throw; 被指定为重新使用现有的临时文件。
  • @Phil:检查了更有效的 C++ 项目 12,对象切片确实发生了。将我的答案回滚到原始答案。
  • @Managu - 通过指针投掷/捕捉确实按预期工作。不同的是,指针的值是地址,而引用的值是它所引用的(即使它是通过指针实现的)
【解决方案6】:

如果你有一个异常层次结构,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 的输出,这可能是您期望得到的。

【讨论】:

  • 谢谢。这很令人惊讶。我认为在通过引用处理对象时不会发生切片。
【解决方案7】:

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

【讨论】:

  • 任何未捕获的抛出都将调用unexpected(),除非另有说明(名称来自内存),否则它将调用terminate()。在这种情况下,裸 throwthrow something 有什么区别?
  • @David,我认为亚当的意思是“投掷”;当处理程序未处于活动状态时。也就是说,在任何动态异常处理程序范围之外,它将调用 std::terminate (它不需要出现在异常处理程序的大括号内,但这样的处理程序必须在之前输入并且不能留在当前执行中序列)。
【解决方案8】:

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

欢迎大家来看看

【讨论】:

    猜你喜欢
    • 2018-02-19
    • 2018-05-30
    • 1970-01-01
    • 2012-02-27
    • 1970-01-01
    • 2018-02-27
    • 2020-08-03
    相关资源
    最近更新 更多