5

为什么从类 A 的构造函数中抛出的以下异常会被捕获两次,第一次被构造函数本身的 catch 捕获,第二次被 main 函数中的 catch 捕获?

为什么它不被构造函数中的 catch 捕获一次?

 #include <iostream>
    using namespace std;

    class E {
       public:
          const char* error;
          E(const char* arg) : error(arg) { }
    };

    class A {
       public:
          int i;

          A() try : i(0) {
             throw E("Exception thrown in A()");
          }
          catch (E& e) {
             cout << e.error << endl;
          }
    };

    int main() {

       try {
          A x;
       }
       catch(...) 
       {
        cout << "Exception caught" << endl; 
       }
    }

如果我删除 main 函数中的 try-catch 块,程序将崩溃。这是输出:

Exception thrown in A()
terminate called after throwing an instance of 'E'
zsh: abort (core dumped)  ./main

为什么在 main 函数中没有 try-catch 块它会崩溃?

4

3 回答 3

3

构造函数中的函数尝试块不能防止异常。一旦构造函数中发生异常,您就没有 object,并且异常必须传播。function-try-block 唯一能做的就是一些本地清理。

就函数尝试块而言,构造函数确实是一种非常特殊的动物。

参照。C++11 15.3/14:

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


Tl;dr:永远不要使用函数尝试块。

于 2013-10-30T15:48:53.883 回答
2

这似乎是合乎逻辑的。考虑以下两种情况。

一世。Try 块在构造函数的主体内:

  A() : i(0) {
    try
    {
       throw E("Exception thrown in A()");
    }
    catch (E& e) {
       cout << e.error << endl;
    }
    // If code reaches here,
    // it means the construction finished well
  }

ii. Try 块在初始化器 ctor 中:

  A() try : i(0) {
     throw E("Exception thrown in A()");
  }
  catch (E& e) {
     cout << e.error << endl;

     // OK, you handled the exception,
     // but wait you didn't construct the object!
  }

在第一种情况下,发生异常后,您将在构造函数中处理它,然后您将正确构造对象。

在第二种情况下,发生异常后,您将在那里处理它。但是您还没有构造对象,并且调用方没有对象。调用者应处理未构造的对象情况。

于 2013-10-30T15:51:38.700 回答
2

您正在使用一个名为function-try-catch的功能。在构造函数中使用时,它允许在初始化列表中捕获异常(对于在基类构造函数中捕获异常特别有用)以及构造函数主体。但是由于异常是在构造函数中抛出的,所以类是不完整的,所以编译器会自动重新抛出任何捕获的异常。这就是为什么你看到它被抓了两次。

阅读以下文章了解更多详情:

C++ 中的构造函数和异常

于 2013-10-30T15:59:24.473 回答