容错性:

1、我们希望使用者有试错的机会,能够继续运行,而不希望一旦出错就退出。如果没有这种操作,我们也需要将出错的消息反馈给使用者。

当发生异常的时候可以选择就地处理,但也可以选择不就地处理。抛出异常再处理就是后者。有些就地处理会影响到程序的主逻辑,而且有地模块是最底层的模块,它是没有办法知道该如何处理这个异常的,所以需要抛出异常给调用者,由调用者捕获并选择是否处理。

各种步骤都判断成功与否,或者要输出反馈,这对于程序的主逻辑是不利的。

将有可能发生异常的情况都放在了try模块中,并尝试处理(不处理或者抛出)。

异常处理模块是我们可以专注程序的主逻辑。

2、异常处理:抛出、捕获、处理。

异常的抛出都是向他的上级调用者,异常处理的基本思想:

                                              【12】C++进阶系列(异常处理)

这样的级层关系,使得可以在不同的位置处理不同的异常,方便我们专注于程序主逻辑的设计。

异常处理的语法:抛出和捕获的配合

【12】C++进阶系列(异常处理)

例子:除数为0的异常

#include<iostream>
using namespace std;

int divide(int x, int y) {
	if (y==0)
	{
		throw x;
	}
	return x / y;
}

int main() {
	try
	{
		cout << "5/2=" << divide(5, 2) << endl;
		cout << "8/0=" << divide(8, 0) << endl;
		cout << "7/1=" << divide(7, 1) << endl;
	}
	catch (int e)
	{
		cout << e << "is divided by zero!" << endl;
	}
	cout << "That is ok." << endl;
	return 0;
}

 

【12】C++进阶系列(异常处理)异常接口声明:

可以在函数的声明中列出这个函数可能抛出的异常类型。例如:void fun() throw(A,B,C,D);

若无异常接口声明,则表示此函数可以抛出任何类型的异常。

肯定不抛出任何类型异常的函数声明如下:void fun() throw();括号里面没有任何参数

3、异常处理中的构造和析构

问题:抛出异常之后,throw语句后面的语句不再执行,当前程序块没有执行到 “}”的部分,所以当前“{ ……}”中的函数没有被析构。那么是怎样的机制来处理这部分的析构呢?——自动的析构

找到一个匹配的catch异常处理之后:

初始化异常参数

将对应的try块开始到异常被抛出处之间构造(且尚未析构)的所有自动对象进行析构。

从最后一个catch处理之后开始恢复执行。

比如:抛出一场之后Demo d是怎么析构的呢?

#include<iostream>
#include<string>

using namespace std;
class MyException
{
public:
	MyException(const string & message):message(message){}
	~MyException() {}
	const string &getMessage()const { return message; }
private:
	string message;
};

class Demo
{
public:
	Demo() { cout << "Constructor of demo." << endl; }
	~Demo() { cout << "Destructor of demo" << endl; }
	
private:

};
void func() throw(MyException) {
	Demo d;
	cout << "Throw MyException in func()" << endl;
	throw MyException("exception thrown by func()");//这时d还没有析构,中途抛出异常终止了函数的执行,此时程序回到调用者(主函数func())
}                                                   //执行到这里d才会析构

int main() {
	cout << " In main function" << endl;
	try
	{                                               //异常处理机制保证进入try之后,抛出异常之前构造的对象 d 析构完成。然后才进入catch块里面处理异常
		func();
	}
	catch (MyException &e)
	{
		cout << "Caught an exception:" << e.getMessage() << endl;

	}
	cout << "Resume the execution of main()" << endl;
	return 0;
}

【12】C++进阶系列(异常处理)

4、标准程序库异常处理

继承关系:exception是所有异常类的基类

【12】C++进阶系列(异常处理)

异常类:

【12】C++进阶系列(异常处理)

标准异常类的基础:

exception:标准程序库异常类的公共基类

logic_error:表示可以在程序中被预先检测到的异常。如果小心的写程序,这类异常能够避免

runtime_error:表示难以被预先估计检测的异常。

例子:求解三角形面积

#include<iostream>
#include<cmath>
#include<stdexcept>//向函数传入了无效参数(invalid_argument)的头文件

using namespace std;

double area(double a, double b, double c) throw(invalid_argument) {
	//判断三角形边长是否为正
	if (a<0|b<0|c<0)
	{
		throw invalid_argument("the side length should be positive");
	}
	//判断三边长是否能构成三角形
	if (a+b<=c||a+c<=b||b+c<=a)
	{
		throw invalid_argument("the side length should fit the triangle inequation");
	}
	//由Heron公式计算三角形面积
	double s = (a + b + c) / 2.0;
	cout<<sqrt(s*(s - a)*(s - b)*(s - c));
}

int main() {
	double a, b, c;
	cout << "Please input the side length of a triangle:" << endl;
	cin >> a >> b >> c;
	try
	{
		area(a, b, c);
	}
	catch (exception &e)
	{
		cout << "Error:" << e.what() << endl;
	}
	return 0;
}

************************************************************************************************

写在最后,整个系列看完。刚好一个月

人艰不拆

相关文章: