【问题标题】:C++: Should I catch all exceptions or let the program crash?C++:我应该捕获所有异常还是让程序崩溃?
【发布时间】:2014-11-29 00:12:03
【问题描述】:

我有一个用 (Visual) C++ 编写的 Windows 服务,它具有非常详细的日志记录功能,它经常帮助我找到客户有时遇到的错误的原因。基本上我检查每个返回值并记录发生了什么以及错误来自哪里。

理想情况下,我希望对异常(如数组超出范围、除以零等)具有相同级别的详细可见性。换句话说:我想确切地知道异常来自哪里。出于可读性和实用性的原因,我不想将每几行代码都包装到单独的 try/catch 块中。

我今天拥有的是一个通用的包罗万象的方法,它可以捕获所有内容并在关闭程序之前记录错误。从用户的角度来看,这很好 - 干净关闭而不是应用程序崩溃 - 但对我来说很糟糕,因为我只从异常中得到一般消息(例如“数组超出范围”),但不知道它来自哪里。

去掉catch-all 并让程序崩溃不是更好吗?我可以指示客户让Windows 创建应用程序崩溃转储(如here 所述)。使用转储文件,WinDbg 会准确地指向代码中引发异常的位置。

【问题讨论】:

  • 如果应用程序意外崩溃,这对客户不利,尽管这很正常。如果它永远不会崩溃,那就更好了。而且,如上所述,catch(...) 使调试成为一场噩梦。最初,让客户目睹严重崩溃可能很糟糕,但随着这些事件被报告,它们将变得越来越少(理论上),直到它接近 0。
  • @RPGillespie:谢谢,这或多或少也是我的理由。如果我没记错的话,崩溃是我找到并修复可能引发异常的代码区域的唯一方法。
  • 在编写良好的 c++ 程序中,没有任何理由可以引发除以零错误或其他逻辑错误。这是程序设计草率的指标。
  • @RichardHodges:请详细说明如何保证永远不会出现这样的错误。
  • @RichardHodges:这个问题是关于寻找这些东西可能被遗忘的地方。或者在不是我编写的库代码中可能引发了异常,因此我无法控制。

标签: c++ windows exception crash minidump


【解决方案1】:

去掉包罗万象,让程序运行不是更好吗? 而是崩溃?

你可以包罗万象

  • 写一条(更私人的)关于发生的致命错误的消息,强制关闭应用程序。不要让程序继续:你不知道发生了什么,在哪里。继续可能会导致用户数据损坏、后续错误等。
  • 告诉用户与您联系,详细说明他们做了什么以及发生了什么。
  • 告诉用户包含您的应用程序生成的日志文件。

如果你不做这样的事情,那么你还不如去掉包罗万象的东西。

出于可读性和实用性的原因,我不想换行 每隔几行代码分成单独的 try/catch 块。

然而,如果您希望您的程序能够恢复,这正是您必须做的。你能做的是

  • 告诉用户发生了什么事,也许是输入错误导致了它。不要让它听起来很技术性。
  • 保存用户输入的所有数据,以免他们的工作完全丢失
  • 您知道失败发生在哪一步。撤消该步骤,即丢弃对象/数据,并返回到异常之前的点。
  • 恢复用户从第二点输入的数据,这样他们就不需要从头开始重复操作。

关键是您的程序可以返回到有效状态。

【讨论】:

    【解决方案2】:

    您可以抛出异常并说明错误发生的位置和原因:

    throw std::string("could not open this file");
    

    如果您不想为每个可能的错误编写不同的描述,您可以使用标准宏 __FILE__ 和 __LINE__:

    #define _MyError std::string("error in " __FILE__ + std::to_string(__LINE__))
    // ...
    throw _MyError;
    

    如果源文件名和错误行不够,并且您需要更多信息,例如堆栈跟踪或内存值,您的程序可以生成调试报告。 Google Breakpad 是一个 C++ 库,可让您以可移植的方式执行此操作。 wxWidgets 库中的 wxDebugReport 类是另一种选择。在 Windows 上,调试报告可能包含一个可以在 Visual Studio 中加载的小型转储文件,并允许您以类似于调试的方式分析错误。

    【讨论】:

    • 请确保你抛出的任何东西都来自std::runtime_error或std::logic_error。通过抛出最终不是从 std::exception 派生的对象,您将撤消放入 c++11 <exception> 标头中的所有良好工作。
    【解决方案3】:

    您可以通过调用AddVectoredExceptionHandler 注册自定义的向量异常处理程序。

    每当抛出异常时都会调用它,并且您可以在其中生成一个堆栈跟踪,然后您可以将其保存用于记录目的。

    编写代码来做到这一点并非完全是微不足道的,但也不是火箭手术。

    我从来没有亲自用 C++ 完成过,但如果没有现成的库可以在某个地方执行此操作,如果您没有时间或没有意愿自己动手,我会感到惊讶。

    【讨论】:

    • AddVectoredExceptionHandler 看起来很有希望。但是,它的文档并不完全清楚,而且 MSDN 的示例明确地仅适用于 32 位。是否有更好的文档和示例代码可用?
    • 我发现文档足以满足我的需要。请随时提出有关它的具体问题,如果有任何问题,我(或其他人)会尽力提供帮助。
    猜你喜欢
    • 1970-01-01
    • 2014-06-25
    • 2013-09-05
    • 1970-01-01
    • 2010-09-10
    • 2021-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多