32

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

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

4

4 回答 4

44

Herb Sutter 和 Andrei Alexandrescu 的《C++ 编码标准》一书包含一整章关于错误处理和异常的内容,包括

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

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

于 2008-10-23T19:50:35.080 回答
13

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

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

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

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

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

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

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

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

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

于 2009-04-11T14:50:39.513 回答
6

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

于 2008-10-23T19:39:37.923 回答
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...
  }
}
于 2008-10-23T20:11:41.400 回答