c++中的错误 exception

c++中的异常 exception

变成入门的时候可能经常遇到的错误:

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;
}
随便测试了一下,结果如下:

c++中的错误 exception

可以看到程序是直接结束了,并没有理会那个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;
}
运行结果:

c++中的错误 exception

可以看到现在我们可以知道是哪个地方除了问题,并且可以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;
}
运行结果如下:

c++中的错误 exception

这里大家可能会疑惑,因为在正常的函数参数传递中,我们传递引用就是为了避免重复地构造对象,但是在try...catch...中就不一样了,throw在抛出异常的时候,无论catch是接受引用传递还是接受值传递,编译器都会在throw异常时新建一个临时对象,所以才会有上面结果中显示的两次构造MyException对象,而catch中的引用不过是指向这个临时对象而不是原本的那个MyException对象,一搬都是吧抛出异常跟新建异常对象合并在一起,这样更简洁,所以上面抛出异常可以写成

throw MyException("Divisor is not allowed to be 0");
本来还想说一下exception和他的一些派生类的,不过好像网上挺多这些东西的,也没什么可讲的,就收工了吧

大家有兴趣可以到这里去了解一下c++自带的标准异常类,都是一些形式性的东西,不难滴~~