变成入门的时候可能经常遇到的错误:
this application has requested the runtime to terminate it in an unusual way. Please contact the application's support team for more information
这是由于程序在运行时发生了未知的错误,例如:打开不存在的文件,爆栈,除数为0等错误,程序直接调用abort()函数直接终止程序的运行;当然,显示的信息不一定就是上面这一条
上面这个情况是程序自己解决异常的问题,这种方式实际上是非常粗暴的,直接终止了程序运行,而且你还不知道程序错在哪个位置,是因为什么错(当然,用万能的cout强行追踪也是阔以滴,哈哈)
所幸,c++引入了比较优雅的try... catch....异常机制来让程序猿自己处理可能出现的异常,这种机制实际上是避免了程序直接调用abort()函数,使程序看起来更优雅一点,具体结构如下:
try{ // 可能会引发异常的代码块 }catch(exception argument){ //处理捕捉到的异常 }
try...catch...机制实际上主要是以下几个部分:
1.将可能引发异常的代码(如:文件读取等)放入try块中
2.判断在什么时候抛出异常,也就是可能引发异常的代码块中需要添加异常抛出的语句,抛出异常通常使用 throw关键字
3.catch首先通过异常参数列表匹配产生的异常,如果匹配成功,那么执行catch块的代码
先写一个简单的例子
首先是没有异常处理的
#include <iostream> using namespace std; int division(int a, int b){ return a / b; } int main(){ int a, b; while(1){ cout << "Please input a and b: "; cin >> a >> b; cout << "a / b = " << division(a, b) << endl; } return 0; }
随便测试了一下,结果如下:
可以看到程序是直接结束了,并没有理会那个while(1)
那我们现在来加一下异常
#include <iostream> using namespace std; int division(int a, int b){ <span style="white-space:pre"> </span>if(b == 0) <span style="white-space:pre"> </span>throw "Divisor is not allowed to be 0"; <span style="white-space:pre"> </span>return a / b; } int main(){ <span style="white-space:pre"> </span>int a, b; <span style="white-space:pre"> </span>while(1){ <span style="white-space:pre"> </span>cout << "Please input a and b: "; <span style="white-space:pre"> </span>cin >> a >> b; <span style="white-space:pre"> </span>try{ <span style="white-space:pre"> </span>cout << "a / b = " << division(a, b) << endl; <span style="white-space:pre"> </span>cout << "successful division" << endl; <span style="white-space:pre"> </span>}catch(const char* msg){ <span style="white-space:pre"> </span>cout << "Error message is: " << msg << endl; <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span> <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>return 0; }
运行结果:
可以看到现在我们可以知道是哪个地方除了问题,并且可以print出异常信息,更重要的是,程序依然可以继续往下执行
可以看到,在产生异常之后,程序马上跳转到匹配的catch块执行,而终止try块中代码的执行
当然,如果没有匹配上产生的异常(上面这个例子只是简单的匹配字符串,实际上更常用的是异常对象匹配),那么程序同样会调用abort()函数,然后编译器给你提示一堆错误的信息时候,你的程序就挂掉了
看了上面这个例子,是不是感觉try和catch有一点实参和型参的感觉
那下面我们来看一个例子
我们现在吧异常当作一个MyException的对象来处理:
#include <iostream> using namespace std; class MyException{ public: MyException(){ msg = ""; cout << "in the default constructor" << endl; } MyException(MyException &aa){ msg = aa.msg; cout << "in the copy constructor" << endl; } MyException(string msg_){ msg = msg_; cout << "in the string constructor" << endl; } string what(){ return msg; } string msg; }; int division(int a, int b){ if(b == 0){ MyException me("Divisor is not allowed to be 0"); throw me; } return a / b; } int main(){ int a, b; while(1){ cout << "Please input a and b: "; cin >> a >> b; try{ cout << "a / b = " << division(a, b) << endl; cout << "successful division" << endl; }catch(MyException &ME){ cout << "Error message is: " << ME.what() << endl; } } return 0; }
运行结果如下:
这里大家可能会疑惑,因为在正常的函数参数传递中,我们传递引用就是为了避免重复地构造对象,但是在try...catch...中就不一样了,throw在抛出异常的时候,无论catch是接受引用传递还是接受值传递,编译器都会在throw异常时新建一个临时对象,所以才会有上面结果中显示的两次构造MyException对象,而catch中的引用不过是指向这个临时对象而不是原本的那个MyException对象,一搬都是吧抛出异常跟新建异常对象合并在一起,这样更简洁,所以上面抛出异常可以写成
throw MyException("Divisor is not allowed to be 0");
本来还想说一下exception和他的一些派生类的,不过好像网上挺多这些东西的,也没什么可讲的,就收工了吧
大家有兴趣可以到这里去了解一下c++自带的标准异常类,都是一些形式性的东西,不难滴~~