【问题标题】:Can I catch an exception thrown before main()?我可以在 main() 之前捕获异常吗?
【发布时间】:2017-06-24 16:11:19
【问题描述】:

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

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

给予

terminating with unexpected foreign exception
Abort (core dumped)

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

【问题讨论】:

  • 您的目标是哪个操作系统?
  • 首先,在调用main 之前不可能捕获异常,除非您在调试器中运行。其次,捕获这样的异常几乎没有用,因为您的程序很可能无论如何都无法继续。最后,您确定这是抛出 C++ 异常,而不是操作系统或硬件异常吗?这些是使用相同术语的不同事物。
  • "(用不同的编译器编译)"不要这样做
  • @LightnessRacesinOrbit 提到使用不同的编译器可能是一个原因。但这实际上取决于“其他”编译器。和“当前”编译器。不幸的是,我们都不知道。
  • 如果它是一个共享库,您可以将库加载推迟到 main() 启动之后 - 要么不链接它并使用显式 dlopen(),要么将其标记为延迟加载在您的链接器标志中。

标签: c++ exception terminate


【解决方案1】:

一般来说,在标准 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,直到其中一个成功(即,如果第一次抛出异常,第二次调用将尝试构造thing,等等)。然而,如果程序中the_x() 的第一次调用可以被识别并捕获到异常(即将它包装在try/catch 中),则没有必要从后续调用中捕获异常 - 因为,如果第一次调用不抛出,thing构造成功,不再构造。

【讨论】:

    【解决方案2】:

    我发现这很有趣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会在任何实例化之前被调用。

    【讨论】:

    • 不完全是“全局尝试...捕获”。更像是一个 catch 内部终止(你仍然不能继续执行)。
    猜你喜欢
    • 2012-04-11
    • 1970-01-01
    • 2018-05-09
    • 2023-03-14
    • 1970-01-01
    • 2017-10-08
    • 2011-12-05
    • 1970-01-01
    • 2011-02-12
    相关资源
    最近更新 更多