【问题标题】:Losing exception type when rethrowing an exception from a catch block从 catch 块重新抛出异常时丢失异常类型
【发布时间】:2012-09-14 21:48:40
【问题描述】:

今天我在catch 块中发现了一个错误:

catch (const exception& e){
    // do something
    // throw e; <-- bug!
    throw;    // <-- right thing to do
}

基本上,如果我重新抛出异常e 显式,我会得到一个新的std::exception 重构,实际上来自what() 方法的消息是默认的std::string,而不是我的自定义构建的消息。

解释是什么?我以为throw;只是throw ExceptionJustCaught;的简写。

【问题讨论】:

  • 这是值和引用之间的区别。
  • 这是一个非常重要的概念,但经常被忽视(在我看来,这是一个棘手的语法,在编译时至少应该是一个警告......)。好问题!

标签: c++ exception try-catch


【解决方案1】:

只是一个throw 通过引用抛出当前异常。 throw e copy 构造一个新的异常来抛出。这与return 的工作方式大致相同。

【讨论】:

  • “参考”。确切地说,这不应该失去what() 的正确实现,它承载了我的信息。
  • 您能否发布一个完整的、可编译的代码示例,并尽可能少地说明问题?很可能,您的复制构造函数不会保留该消息。
  • Kerrek 的答案看起来是正确的,我怀疑存在切片问题,所以我不会编辑问题,因为我认为它已正确回答。也许大卫的说法是对的,只是措辞不同,但说实话还不够清楚。
  • @LorenzoPistone:我们说的是同一件事。 return 也会有同样的问题。
【解决方案2】:

异常对象有点特殊。它们是在内存中的一个特殊位置构建的,它们的生命周期由它们被捕获的 catch 块决定。

如果你说throw e;,原始异常的生命周期在catch块的末尾结束,你通过复制e抛出一个新的异常,从而产生一个经典的切片问题:由于e 是对动态类型通常比std::exception 派生更多的对象的多态引用,因此您最终会切掉对象的派生部分。

相比之下,throw; 是重新激活原始异常的特殊语句,因此它不再被捕获,并且它的生命周期不再在块的末尾结束。事实上,如果您通过非常量引用捕获,您可以继续修改异常对象并重新抛出,从而将状态更改传递到较低的捕获块。但请记住,重新抛出与抛出新异常不同!

【讨论】:

    猜你喜欢
    • 2014-06-19
    • 1970-01-01
    • 2020-09-27
    • 2014-10-27
    • 2012-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多