【问题标题】:Why is my exception still being thrown after being caught?为什么我的异常被捕获后仍然被抛出?
【发布时间】:2013-12-03 01:49:41
【问题描述】:

我有以下代码,其中使用函数调用的结果初始化变量。这个函数会抛出,所以我设置了一个 try-catch 来捕获异常。出于某种原因,即使在 catch 子句运行后,异常仍会显示在屏幕上。

#include <iostream>
#include <stdexcept>

int f() { throw std::invalid_argument("threw"); return 50; }

struct S
{
    S()
        try : r(f())
    {
        std::cout << "works";
    }
    catch(const std::invalid_argument&)
    {
        std::cout << "fails";
    }

    int r;
};

int main()
{
    S s;
}

此代码在显示异常后打印“失败”:

terminate called after throwing an instance of 'std::invalid_argument'
what():  threw

为什么仍然抛出异常?我在 main 中设置了相同的代码,它可以正常工作:

int main()
{
    try { throw std::invalid_argument("blah"); }
    catch(const std::invalid_argument&) { }
}

那么为什么在初始化列表中使用它会失败?

【问题讨论】:

  • 这是在某处的标准中定义的...{S s; cout&lt;&lt;s;} 如果s 构造失败,你会期待什么?
  • 我认为你在构造函数初始化列表中抛出的因素可能是相关的。如果列表抛出,您将无法访问 ctr body,因此编译器可能认为 catch 是它尚未启用的主体的一部分。我希望您在 ctr 正文中分配 r ,它的行为会比预期的要好得多。
  • 这真的很值得一读:gotw.ca/gotw/066.htm,这也是:stackoverflow.com/questions/7110636/…
  • 请注意,catch 处理程序正在您的代码中输入;如果您刷新流 @​​987654330@ 将被打印。当控制到达函数 try 块的末尾时,将重新抛出异常,这就是它们的工作方式。

标签: c++ c++11 exception-handling


【解决方案1】:

带有函数 try 块的构造函数(例如 S 的构造函数)会自动重新抛出 catch 块捕获的任何异常。因此,在catch 捕获异常之后,它会重新抛出它。这种行为不同于普通的catch 处理程序,后者不这样做。我认为基本原理是,如果数据成员或基类的构造失败,则对象构造失败。 catch 处理程序的目的只是在异常向外传播之前进行任何额外的清理。

希望这会有所帮助!

【讨论】:

    【解决方案2】:

    来自 C++11 标准,15.3/15:

    如果控制到达 function-try-block 的处理程序的末尾,则重新抛出当前处理的异常 构造函数或析构函数。

    原因在您的问题下的 GOTW Jerry 链接中得到了很好的解释,但概括地说:想象一下,如果它没有重新抛出,那么 S s; 之后的下一行可能会尝试使用 s,尽管它从未完成构建,并且当s 离开作用域时,构造函数将安排调用s 的析构函数——可能释放从未初始化的指针、释放从未使用的锁等。

    相比之下,如果您让数据成员默认初始化,然后从构造函数主体中的 try/catch 块分配给它,则对象的状态(包括基数和数据成员)可能会保持某种连贯状态:作为程序员,您可以决定该状态是否正常 - 即您是否将在构造函数主体中使用 try/catch 块,并让以后的成员函数处理可能默认构造的数据成员。

    【讨论】:

      猜你喜欢
      • 2020-12-10
      • 1970-01-01
      • 2014-08-16
      • 1970-01-01
      • 2010-11-16
      • 2012-01-22
      • 2015-06-23
      相关资源
      最近更新 更多