【问题标题】:In a C++ command-line application, how should I catch exceptions at the top-level?在 C++ 命令行应用程序中,我应该如何在顶层捕获异常?
【发布时间】:2026-02-05 18:40:01
【问题描述】:

我正在用 C++ 编写一个命令行应用程序。如果发生未处理的异常,我不希望应用程序严重崩溃,而是尽可能清理并打印错误消息。

我应该如何在顶层捕获异常以避免程序崩溃?我应该抓住std::exception... 还是别的什么?

【问题讨论】:

  • 您应该捕获应用程序将抛出的任何异常。由于您是编写应用程序的人,因此只有您(而且 *.com 上没有其他人)可能知道您未来的应用程序可能会抛出哪些异常。
  • 请注意,如果在异常向上传播时发生堆栈展开,则它是由实现定义的。如果你等到main,你可能无法清理任何东西。
  • @NathanOliver - 如果在main捕获 异常,一切都会得到适当的清理。只有当它 main 传播(即,terminate 被调用,因为没有异常处理程序)时,它可能会或可能不会破坏自动对象。
  • @PeteBecker 我的印象是,如果异常是在调用链中引发的,并且它会向后传播调用链,以寻找它实现定义的处理程序,如果它在途中展开调用堆栈备份。不是这样吗?调用链下游的本地函数对象会得到正确处理吗?
  • @NathanOliver - 当捕获到异常时,调用链下游的自动变量都已被销毁。这是 RAII 的基础。

标签: c++ exception exception-handling


【解决方案1】:

您可以执行的清理质量取决于所引发的异常。

例如,您自己提出的异常(可能源自std::exception;我们称之为fooexception)可以很好地处理。

所以你真的想要一个关于这些行的捕获站点

try {
    /*whatever*/

} catch (fooexception& fe){
    /*ToDo - handle my exception*/
} catch (std::exception& e){
    /*ToDo - handle this generically*/
} catch (...){
    /*Hum. That's bad. Let's do my best*/
}

您可以随意扩展。请记住,在某种意义上,多个 catch 块的行为类似于 if else 块:始终先排序,具体例外。

【讨论】:

    【解决方案2】:

    嗯,你可以同时抓住两个:

    int main() {
        try {
            // do stuff
        }
        catch(const std::exception& e) {
            std::cout << "Caught exception: " << e.what() << std::endl;
        }
        catch(...) {
            std::cout << "Caught unknown exception." << std::endl;
        }
    }
    

    【讨论】:

      【解决方案3】:

      你应该抓住两者,甚至更多。如果您在调用堆栈中的某处使用了更具体的异常类型,请尝试捕获它。

      考虑代码:

      try
      {
          process();  
      }
      catch (const SpecificException& ex)
      {
          std::cerr << "SpecificException occured: " << ex.what() << std::endl;
      }
      catch (const std::runtime_error& ex)
      {
          std::cerr << "std::runtime_error occured: " << ex.what() << std::endl;
      }
      catch (...)
      {
          std::cerr << "Unknown error occured!" << std::endl; // should never happen hopefully
      }
      

      请记住始终按异常的特定性进行排序 - 更专业/派生的优先,因为运行时将停止在第一个能够处理异常的 catch 块(即第一个具有异常类型匹配或作为基础的 catch 块) .

      【讨论】: