C++错误处理——示例代码的良好来源

C++ Error Handling -- Good Sources of Example Code?

本文关键字:错误 处理 C++ 代码      更新时间:2023-10-16

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

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

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

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

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

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

对程序流使用错误代码。如果出现预期的错误,请不要引发异常。例如,您正在读取一个文件,您可能会为"找不到文件""文件锁定"抛出异常;但永远不要为"文件结尾"抛出一个。

如果你这样做了,你就永远无法编写简单的循环,你总是会把代码包装在异常处理程序中。别忘了,异常速度非常慢,这在大型多线程服务器中尤为重要。(在桌面应用程序中根本不那么重要)。

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

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

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

所以希望我给了你足够多的思考。简单的事实是,风格在错误处理中毫无意义,实用性就是一切。如果你必须把日志语句放在任何可能发生错误的地方,那就这样做吧。你可以看到代码哪里出了问题(以及处理了什么数据),这比你有一个优雅的异常层次结构或你的代码中到处都是异常处理程序更重要如果您无法轻松跟踪错误,那么您的错误处理代码将毫无用处

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

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

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

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

在我看来,除了例外(也是最常被打破的规则),最基本的规则是这样的。除非您有处理异常的特定计划,否则不要试图捕捉异常

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

在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...
  }
}