变成入门的时候可能经常遇到的错误:
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++自带的标准异常类,都是一些形式性的东西,不难滴~~