【问题标题】:C++ Error Handling -- Good Sources of Example Code?C++ 错误处理——示例代码的良好来源?
【发布时间】:2010-09-18 20:52:41
【问题描述】:

几乎每个地方的示例代码都忽略了错误处理(因为它“混淆了示例代码正在解决的问题”)。我的编程知识主要来自书籍和网站,你很少看到那里使用任何错误处理,更不用说好东西了。

在哪里可以看到 C++ 错误处理代码的优秀示例?特定的书籍、特定的开源项目(最好有要查看的文件和功能)以及特定的网页或站点都将被接受。

【问题讨论】:

    标签: c++ error-handling


    【解决方案1】:

    Herb Sutter 和 Andrei Alexandrescu 的书 C++ Coding Standards 包含一整章关于错误处理和异常,包括

    • 大量断言以记录内部假设和不变量
    • 制定合理的错误处理策略,并严格遵守
    • 区分错误和非错误
    • 设计和编写错误安全代码
    • 更喜欢使用异常来报告错误
    • 按值抛出,按引用捕获
    • 适当地报告、处理和翻译错误
    • 避免异常规范

    每个主题还包含一个示例,我发现它是一个非常有价值的资源。

    【讨论】:

    • 不错。我已将其添加到我的购买清单中。 (一旦我可以再次投票,我也会投票给这个答案。:-))
    【解决方案2】:

    “使用异常”“使用错误代码” 从来没有像示例所暗示的那样明确。

    对程序流程使用错误代码。如果您有预期的错误,请不要抛出异常。例如。你正在读取一个文件,你可能会抛出 "file not found", "file locked" 的异常;但永远不要为“文件结尾”抛出一个。

    如果这样做,您将永远无法编写简单的循环,您将始终将代码包装在异常处理程序中。并且不要忘记异常非常慢,这在大型多线程服务器中尤其重要。 (在您的桌面应用程序中一点也不重要)。

    其次,要非常小心异常层次结构。你可能认为有一个Exception 类是可以的,然后从它派生一个NetException,然后为你的SMTP 类派生SMTPException。但是除非您在基类中保存通用数据,否则您将始终必须捕获该层次结构中的每种类型的异常。例如。如果您将 SMTP 错误的原因放在 SMTPException 类中,则必须捕获它 - 如果您只捕获 Exception 类型,您将无法访问 SMTPException 成员。解决此问题的一个好方法是在基异常类中包含一个字符串和一个 int 成员,并且只使用它们,即使对于派生类型也是如此。不幸的是std::exception 只提供了一个字符串:(

    有人说这样做意味着你可能只拥有一个异常类型,特别是因为无论如何你总是会捕获基类类型。

    如果您确实使用了异常,那么您必须不厌其烦地使用比使用错误代码更多的数据来填充它们。出现错误时,您必须立即处理它们,否则它们会在代码中丢失。除了一个例外,它可能会在远离它被抛出的地方很多级别被捕获 - 就像在罗迪的例子中一样。 DoC 被调用,并从 DoA 中获取异常 2 级。除非您将错误指定为特定于 DoA 中的代码,否则您可能会认为它是从 DoB 函数中抛出的。 (简单的例子,但我已经看到在调用堆栈中处理多个级别的异常的代码。这是调试的最佳方式。这尤其适用于 OO 程序)

    希望我已经给了你足够的思考。事情的简单事实是,风格在错误处理中没有任何意义,实用性就是一切。如果您必须在可能发生错误的任何地方放置日志语句,那么就这样做。与拥有优雅的异常层次结构或在代码中乱扔异常处理程序相比,您可以看到代码出错的地方(以及正在处理的数据)更重要。 如果您不能轻松地跟踪错误,那么您的错误处理代码将毫无用处。

    例外是好的,使用它们。但是想想你在做什么,不要滥用或过度使用它们。滥用的异常比没有错误处理更糟糕(因为您可以获取故障转储并查看未处理的异常以在几秒钟内找到错误。如果异常被吃掉并忽略,您就会被塞满)。

    多年来,我发现调试的最大助手是日志记录。写日志,写很多日志。

    【讨论】:

      【解决方案3】:

      我更喜欢本文中讨论的异常处理。它会产生干净的代码,并避免仅仅为了处理异常而显式创建/删除对象。 http://www.informit.com/articles/article.aspx?p=373339

      【讨论】:

      • 好文章,谢谢。 (我今天没有票了,我会在几个小时内投票给这个。)
      【解决方案4】:

      使用 C++,您最终应该得到的错误处理代码不那么明显,因为您可以将大量繁重的工作留给异常处理。

      在我看来,最基本的例外规则(也是最常被破坏的规则之一)就是这个。 除非您有具体的处理计划,否则不要尝试捕获异常。

      有了异常,您不必担心函数返回的错误代码,因为设计良好的函数只会抛出异常。

      在 C 中,典型的错误处理场景如下所示:

      int DoA() 
      {
       if (location == hellInAHandcart)
        return ERROR;
       else
        RETURN OK;
      }
      
      int DoB()
      {
        int err = DoA();
        if (err != OK)
           return err;
        else
           return DoSomethingElse1();
      }
      
      int DoC()
      {
        int err = DoB();
        if (err != OK)
           //Handle My error here in whatever way...
      }
      

      在 C++ 中...

      void DoA() 
      {
       if (location == hellInAHandcart)
        throw Exception("Gone To Hell in a Handcart");
      }
      
      void DoB()
      {
        DoA();
        DoSomethingElse1();
      }
      
      void DoC()
      {
        try
        {
          DoB();
        }
        catch (Exception &E)
        {
          // Handle My error here in whatever way...
        }
      }
      

      【讨论】:

      • 那个,加上“以任何方式”部分,正是我正在寻找的那种东西。
      • 你的比较对我来说不正确。在 C 版本中,您在 DoSomethingElse1 之前测试 DoA 的结果。
      • @olipion:是的,因为它可能会返回错误代码。除了异常,它不需要返回错误码,所以没有什么要检查的。
      猜你喜欢
      • 2011-05-18
      • 2010-09-14
      • 1970-01-01
      • 2012-01-15
      • 2017-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多