前言
在程序运行的时候有时会遇到错误导致程序崩溃无法运行下去。比如申请过多的内存,进行除零的操作。因此最好以一种受控的方法来运行代码,这里就用到了异常处理机制。
异常处理机制可以避免程序终止,而是可以返回一个异常的值来告诉开发人员是哪里发生了错误,以更好地定位错误。
异常处理
在C++中,当异常发生时,会将程序的控制权从这一部分传到另一部分上。
- 引发异常
- 使用处理程序捕捉异常
- 使用try块
程序是通过excetion handler作为异常处理程序来捕获异常,这个异常处理程序就要位于要处理问题的程序块中,并使用catch来捕获。
try标识可能存在异常被激活的代码块,一般来说它的后面会跟上一个或多个catch块,如果没有,那么这个try则会出错。就好比没有else的if出现在程序中。
或者当我们想要抛出一个异常,来看程序会作出怎么样的应答,就可以使用throw来抛出一个异常。
double hmean(double a, double b) {
if (a == -b)
throw "bad hmean() arguments : a = -b not allowed!!!";
return 2.0 * a * b / (a + b);
}
int main() {
double x = 1, y = -1, z;
try {
z = hmean(x, y);
}
catch (const char* s) {
std::cout << s << std::endl;
}
std::cout << "the result of hmean function is : " << z << std::endl;
return 0;
}
栈解退
假设try没有直接调用引发异常的函数,而是调用了引发异常的函数所调用的函数,那么程序的流程就会从引发异常的函数跳到包含try和处理程序所在的函数中。
现在假设函数由于出现异常而终止,那么程序就需要释放栈中的内存,但不会再释放栈的第一个返回地址后就停止,而是继续释放,不断返回被调用的函数地址,直到找到一个try块。
class bad_hmean
{
private:
double v1;
double v2;
public:
bad_hmean(double a = 0, double b = 0) : v1(a), v2(b) {}
void mesg();
};
inline void bad_hmean::mesg(){
std::cout << "gmean" << v1 << " " << v2 << "invalid arguments: a= -b" << std::endl;
}
class bad_gmean
{
public:
double v1;
double v2;
bad_gmean(double a = 0, double b = 0) : v1(a), v2(b) {}
const char* mesg();
};
inline const char* bad_gmean::mesg() {
return "gmen() arguments should be >= 0";
}
double hmean(double a, double b) {
if (a == -b)
throw bad_hmean(a, b);
return 2.0 * a * b / (a + b);
}
double gmean(double a, double b) {
if (a < 0 || b < 0)
throw bad_gmean(a, b);
return std::sqrt(a * b);
}
int main() {
double x = 5, y = -1, z;
try {
z = hmean(x, y);
std::cout << "harmonic mean of " << x << " " << y << "is " << z << std::endl;
std::cout << "geometric mean of " << x << " " << y << "is " << gmean(x, y) << std::endl;
}
catch (bad_hmean &bg) {
bg.mesg();
std::cout << "try again!!!" << std::endl;
}
catch (bad_gmean &hg) {
std::cout << hg.mesg() << std::endl;
std::cout << "value used :: " << hg.v1 << " " << hg.v2 << std::endl;
}
std::cout << "the result is " << z << std::endl;
return 0;
}
exception类
在C++中定义了exception类,它里面有一个名为what()的虚拟成员函数,以一个字符串返回。此外,exception可作为其他异常类型的基类,如:
- length_error 字符串长度超过了最大允许长度
- out_of_bounds 索引错误
- invalid_argument 无效的入参
- bad_alloc 申请内存发生的异常
最后
异常处理对于项目来说极为重要,因为它可以避免程序的崩溃,当发生错误的时候可以让用户重新输入来让程序继续运行下去。一方面这也增加了编程的工作量,增大程序,降低运行速度,另一方面,这也可以使开发人员了解是什么异常被引发的,以及知道它们背后的原因,发生的时间等等。