Skip to content

Latest commit

 

History

History
97 lines (72 loc) · 4.06 KB

File metadata and controls

97 lines (72 loc) · 4.06 KB

二十五、异常处理

异常处理允许程序员处理程序中可能出现的意外情况。

抛出异常

当函数遇到无法恢复的情况时,它可以生成一个异常来通知调用者函数已经失败。这是通过使用关键字后跟函数想要发送的信号来完成的。当到达该语句时,函数将停止执行,异常将传播到调用方,在调用方可以使用 try-catch 语句捕获异常。

nt divide(int x, int y)
{
  if (y == 0) throw 0;
  return x / y;
}

Try-catch 语句

try-catch 语句由一个 try 块和一个或多个 catch 子句组成,try 块包含可能导致异常的代码,catch 子句用于处理异常。在上面的例子中,抛出了一个整数,因此需要包含一个 catch 块来处理这种类型的异常。抛出的表达式将作为一个参数传递给这个异常处理程序,在这里它可以用来确定函数出了什么问题。注意,当异常被处理后,执行将在 try-catch 块之后继续运行,而不是在 throw 语句之后。

try {
  divide(10,0);
}
catch(int& e) {
  std::cout << "Error code: " << e;
}

异常处理程序可以通过值、引用或指针捕捉抛出的表达式。但是,应该避免按值捕捉,因为这会导致产生额外的副本。通过引用捕获通常是更可取的。如果 try 块中的代码可以抛出更多类型的异常,那么也需要添加更多的 catch 子句来处理它们。请记住,只有与抛出的表达式匹配的处理程序才会被执行。

catch(char& e) {
  std::cout << "Error char: " << e;
}

为了捕捉所有类型的异常,可以使用省略号(...)作为 catch 的参数。这个默认处理程序必须放在最后一个 catch 语句中,因为放在它后面的任何处理程序都不会被执行。

catch(...) { std::cout << "Error"; }

重新引发异常

如果一个异常处理程序不能从异常中恢复,它可以通过使用没有指定参数的关键字throw被再次抛出。这将在调用方堆栈中向上传递异常,直到遇到另一个 try-catch 块。但是要小心,因为如果一个异常从未被捕获,程序将因运行时错误而终止。

int main()
{
  try {
    trythrow 0; }
    catch(...) { throw; } // re-throw exception
  }
  catch(...) { throw; }   // run-time error
}

异常说明

默认情况下,函数允许抛出任何类型的异常。为了指定函数可能抛出的异常类型,可以将throw关键字追加到函数声明中。throw关键字后面是逗号分隔的允许类型列表,如果有的话,用括号括起来。

void error1() {}            // may throw any exceptions
void error2() throw(...) {} // may throw any exceptions
void error3() throw(int) {} // may only throw int
void error4() throw() {}    // may not throw exceptions

这种异常规范与 Java 中使用的非常不同,总的来说,没有什么理由在 C++ 中指定异常。编译器不会以任何方式强制执行指定的异常,也不会因此而进行任何优化。

在 C++11 中不赞成使用throw作为异常规范,它被 noexcept 说明符所取代。类似于throw(),这个说明符表明函数不打算抛出任何异常。主要区别在于 noexcept 支持某些编译器优化,因为如果由于某种原因异常仍然发生,说明符允许程序终止而不展开调用堆栈。

void foo() noexcept {} // may not throw exceptions

异常类

如前所述,任何数据类型都可以在 C++ 中抛出。然而,标准库确实提供了一个名为exception的基类,它是专门设计来声明要抛出的对象的。它在异常头文件中定义,位于std名称空间下。如下所示,该类可以用一个字符串来构造,该字符串成为异常的描述。

#include <exception>
void make_error()
{
  throw std::exception("My Error Description");
}

当捕捉到这个异常时,可以使用对象的函数what 来检索描述。

trymake_error(); }
catch (std::exception e) {
  std::cout << e.what();
}