异常处理¶
引入¶
异常就是在程序执行的时候出现的问题,也就是一些特殊的情况,这时候如果不进行处理很显然就会 Runtime Error,因此异常处理就显得尤为重要。
C++ 的异常处理的关键字为:try
、catch
和 throw
。语法如下所示:
try {
// 这是一段保护代码
} catch (Exception e) {
// 捕获 Exception 类型的代码块
// 如果不需要知道异常产生的原因就不用写变量名
} catch (...) {
// 捕获所有的异常
// 也就是未知异常
}
抛出异常¶
你可以使用 throw
来抛出一个异常。如果嵌套了多层函数的话,那么异常并不会一层一层地回退回去,而是直接退到捕获区那里。例如,可以这样子抛出一个 string
类型的异常:
throw string("好渴鹅吃鱼鱼失败!")
捕获异常¶
在 catch
块里面的语句就是捕获了异常之后要执行的语句。例如这样子:
void eatFish() {
throw string("好渴鹅吃鱼鱼失败!");
}
int main() {
try {
eatFish();
} catch (string e) {
cout << "Error: " << e << '\n';
return 1;
}
return 0;
}
标准中的异常¶
C++ 已经在头文件 exception
当中提供了一些标准异常,我们可以直接在自己的程序里面使用这些标准的异常,也可以以继承的方式定义自己的异常。这是一段定义新的异常的代码:
#include <iostream>
#include <exception>
using namespace std;
class DivByZero {
const char *what() const throw() {
return "除数为零,无法相除!"
}
};
void div(int a, int b) {
if (!b) {
throw DivByZero();
}
return a / b;
}
int main() {
try {
c = div(1, 0);
} catch (DivByZero &e) {
cout << e.what() << '\n';
}
return 0;
}
看到这里,你是不是已经初步掌握了 C++ 异常的处理方法了呢?
该不该使用异常¶
到底该不该在你的程序中使用异常处理呢?我想大概率是应该的。很多人说异常会拖慢程序的速度,还不如使用错误码。但是异常对于新手好,可读性高,错误码只是一个数字,不打注释别人根本就不知道你出现了什么错误?况且我们又不是造火箭,没有必要追求过高的速度。况且 STL 也都使用了异常处理:
_NODISCARD _CONSTEXPR20 const _Ty& at(const size_type _Pos) const {
auto& _My_data = _Mypair._Myval2;
if (static_cast<size_type>(_My_data._Mylast - _My_data._Myfirst) <= _Pos) {
_Xrange();
}
return _My_data._Myfirst[_Pos];
}
这是 vector
的源代码,其中,在 _XRange
函数里面就抛出了异常:
[[noreturn]] static void _Xrange() {
_Xout_of_range("invalid vector subscript");
}
所以对于长点的代码,还是老老实实使用异常吧!