从带有function-try-block的构造函数中抛出异常两次

时间:2013-10-30 15:33:04

标签: c++ exception exception-handling constructor try-catch

为什么从类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

为什么没有主函数中的try-catch块会崩溃?

4 个答案:

答案 0 :(得分:3)

构造函数中的函数try块无法阻止异常。一旦构造函数中发生异常,就没有对象,并且异常必须传播。 function-try-block唯一能做的就是进行局部清理。

构造函数确实是一个关于函数try-blocks的非常特殊的动物。

比照。 C ++ 11 15.3 / 14:

  

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


Tl; dr:永远不要使用function-try-blocks。

答案 1 :(得分: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。尝试块在初始化器中:

  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!
  }

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

在第二种情况下,在异常之后你会在那里处理它。 但是你还没有构造对象,你在调用者身边没有任何对象。调用者应该处理未构造的对象情况。

答案 2 :(得分:2)

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

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

Constructors and Exception in C++

答案 3 :(得分:-1)

你在IDE工作吗?也许是你的调试器第一次捕获异常。您是否在输出中看到文字Exception thrown in A()?我认为你最好通过const引用来捕获异常:

try {
    throw E("Make a simpler test");
} catch (const E& e) {
    cout << e.error << endl;
}