我可以捕获main()之前抛出的异常吗?

时间:2017-02-07 12:05:57

标签: c++ exception terminate

我有一些库(实际上是用不同的编译器编译的tbb库),在main()正确启动之前抛出异常。有没有办法赶上那个?

int main() { std::cout << "Hello World" << std::endl; }

给出

terminating with unexpected foreign exception
Abort (core dumped)

如果我链接到所述库(在此示例中未使用,但在其他代码中将使用它)。

2 个答案:

答案 0 :(得分:2)

一般来说,标准C ++中不可能捕获在构造全局变量期间抛出的异常(在任何函数的范围之外)。

我认为最接近的可能性是使用函数try-block作为静态构造函数的主体。

 class MyStatics
 {
      public:

          MyStatics();

      private:

          X x;    // construction may fail
          Y y;    // construction may fail
            // etc
 };

 static MyStatics all_my_statics;

 MyStatics::Mystatics() : x(), y()   // implement using a function try block
 try
 {
     if (some_condition) throw some_exception();   // construction may even fail here
 }
 catch (SomeException &)
 {
     // handler for SomeException
 }

如果在构造all_my_statics期间抛出异常,那么它的任何完全构造的成员都将被破坏(即MyStatics成员不存在于catch块中。

catch块中,在报告捕获的异常后,没有多少选项。主要选项是;

  • 抛出(或重新抛出)异常(因为MyStatics的构造失败了)。该异常将导致std::terminate()被调用。
  • 以其他方式终止程序,视为“清洁”。

在构造静态期间吞下一个异常并不是一个好主意,因为程序(例如main()内)没有任何迹象表明它所依赖的静态结构没有被正确构造。

将静态对象放在函数

中更为常见
  X &the_x()
  try
  {
       static X thing;
       return thing; 
  }
  catch (Whatever &)
  {
       // handler
  }

请记住,the_x()的每次调用都会尝试构造thing,直到其中一个成功为止(即如果第一次抛出异常,则第二次调用将尝试构造{{1}等等)。但是,如果可以识别程序中的thing的第一次调用并且捕获了它的异常(即将其包装在the_x() / try中),则不必从后续中捕获异常调用 - 因为,如果第一次调用没有抛出,catch的构造已经成功,它将不再构造。

答案 1 :(得分:1)

我发现这个有趣source。它的构建基于std::terminate功能

他建议使用某种全局try...catch(你不能继续运行,但你可以根据例外行事):

[[noreturn]] void onTerminate() noexcept
{
    if( auto exc = std::current_exception() ) { 
        // we have an exception
        try{
            rethrow_exception( exc ); // throw to recognize the type
        }
        catch( MyException const& exc ) {
            // additional action
        }
        catch( MyOtherException const& exc ) {
            // additional action
        }
        catch( std::exception const& exc ) {
            // additional action
        }
       catch( ... ) {
            // additional action
        }
    }

    std::_Exit( EXIT_FAILURE );
}

并在发生异常时注册此调用者,尽可能:

const auto installed{ std::set_terminate(&handler) };

int main() {
    // run...
}

但你必须知道,你不能确定在任何实例化之前会调用std::set_terminate