【问题标题】:Questions about Generic Error Handling in programming关于编程中的通用错误处理的问题
【发布时间】:2011-03-22 16:09:52
【问题描述】:

在谈到错误处理时,我有些困惑。 以 Direct2D 为例。 在开始使用 Direct2D 功能之前,我们必须创建一个 ID2DFactory 对象:

HRESULT hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &d2d1Factory);

从上面可以看到。我们可以检查 HRESULT hr,看看我们是否成功创建了 ID2DFactory。 我认为当这个调用失败时,即使我再次调用它,它仍然会失败。我们没有任何方法可以从这个故障中恢复。

那么检查返回值有什么意义呢?是为了让我们可以在终止程序之前告诉用户出了什么问题吗?

另一个例子是内存不足。当我们遇到罕见的情况时,我们的程序没有足够的内存来“新”一些对象。 在 C++ 中,当内存不足时,new 运算符可能返回 NULL 或引发错误。如果您不测试它是否为 NULL 也不捕获错误,您的程序将终止。我认为您的程序无法从这种情况中恢复过来。

那么,再次检查是否存在您无能为力的严重错误有什么意义?

【问题讨论】:

    标签: c++ error-handling


    【解决方案1】:

    首先,不是每一个错误都不可恢复。示例:如果用户想要打开的文件不可用,程序可能希望向用户报告此情况并要求打开另一个文件。

    其次,即使程序无法继续,它也必须有机会优雅地终止,通知用户问题,保存状态,记录问题以供将来分析等,而不仅仅是崩溃。如果没有错误检查,程序很可能会崩溃。

    【讨论】:

    • +1,错误报告非常重要。简单的例子:想象一下,如果你的代码不正确,编译器会崩溃……错误报告的质量通常是底层程序质量的一个指标。
    【解决方案2】:

    曾经收到客户的错误报告说“它刚刚崩溃”?当错误报告包含错误对话框的屏幕截图时,它们会更有用,说“D2D1CreateFactory 返回 E_...”。

    【讨论】:

      【解决方案3】:

      像 D2D1CreateFactory() 这样的初始化函数可能会失败。此类故障通常意味着您 PC 上的操作系统已完全损坏,您需要重新启动。此信息对用户很有价值,他们想知道“O/S 已冲洗,重新启动并重试”与“在模块 mod.c 中的 2345 处取消引用 nil”。如果您没有捕捉到错误情况,那么您用户所知道的只是程序崩溃了。

      捕获错误返回和异常并将它们报告给用户是区分好程序与差程序的众多因素之一。

      特别是对于 new,您的程序通常有很多选项。它可能能够重新请求较小的初始内存块。它可能能够返回保存缓存值的内存并重试。或许可以保存文件以备退出,也有返还内存的作用。

      当您处理错误返回或异常时,您有四种选择;中止、交替、重试、失败。

      中止就是清理退出;最好返回资源、关闭文件和保存在制品。

      交替就是尝试完全不同的方法来做同样的事情;如果你不能使用http,就像尝试ftp一样。交替是最难的错误恢复方法,坦率地说,大多数情况下只有 NASA 有预算来编写这种错误处理的代码。

      重试就是再次尝试相同的操作。如果失败是暂时的,这可能是成功的。如果故障持续存在,重试可能会导致无限循环,因此重试最好使用限制计数器或呈指数增长的时间延迟。

      失败就是简单地放弃请求或操作并尝试处理下一个请求。 Fail 可能看起来很愚蠢,因为它意味着没有执行请求,没有更新屏幕,或者忽略了用户输入。但令人惊讶的是,用户可以通过在程序外部执行一些操作或在情况不同时重试来从此类错误中恢复过来。事实证明,在大多数情况下,如果程序终止,它会完全拒绝为用户提供服务,用户可能能够使用损坏或部分正确的程序。 (试着想象一个飞行控制系统仅仅因为它取消引用 nil 而中止。这不是你想要的。)

      【讨论】:

        【解决方案4】:

        可能有很多东西需要清理,比如打开的文件句柄,或者一些数据库操作回滚等,在发生错误时需要执行。在某些情况下,错误可能并不严重,程序可能会继续使用部分功能可用,而不是完全崩溃。最后但并非最不重要的一点是,它提供了有关错误发生位置的宝贵信息,这对于调试非常宝贵。

        顺便说一句,除非你使用一些不符合标准的古老编译器,否则new 不能按照 C++ 标准返回 NULL,它必须抛出 std::bad_alloc 异常以防失败。

        【讨论】:

          【解决方案5】:

          检查返回值等对于调试始终至关重要。只需使用宏即可。

          【讨论】:

            【解决方案6】:

            想象两个程序都遇到错误。

            由于内存不足或其他原因导致崩溃,导致非法使用内存,操作系统要么显示一些模糊的错误,要么只是默默地关闭程序。

            另一个应用程序显示一条更简单的错误消息,然后回滚导致错误的操作,以便您决定是否要继续和/或尝试解决导致错误的条件。 (例如,可能关闭一些其他应用程序将允许有更多的内存。)

            您更愿意使用哪个程序?

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2021-06-08
              • 2021-06-29
              • 1970-01-01
              • 1970-01-01
              • 2013-08-26
              • 2013-10-08
              • 2021-11-05
              • 2010-10-02
              相关资源
              最近更新 更多