您的位置:首页 > 编程语言 > C语言/C++

《C++Primer》读书笔记--异常处理

2015-06-14 00:30 323 查看

定义:

异常,让一个函数可以在发现自己无法处理的错误时抛出一个异常,希望它的调用者可以直接或者间接处理这个问题。

之前写的一些小程序,几乎没有用到过异常处理。因为规模比较小,一般的问题在函数内就加上一些判断条件解决了,一般的做法就是返回一个表示错误的值(比如返回NULL指针),在调用的时候判断一下返回的值,虽然简单,但是功能并不强大,只适合小型项目。而大型的项目,如果这么搞就乱套了,所以就要用到异常处理这一套系统。

一个最简单的异常处理:

// ConsoleApplication3.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <vector>
#include <string>
using namespace std;

//异常类
class NumberException{};

void NumOption(const int& a, const int& b)
{
	try
	{
		if (b == 0)
			throw NumberException();
		cout<<a / b<<endl;
	}
	catch(const NumberException& e)
	{
		cout<<"Exception!"<<endl;
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	
	int a,b;
	cin>>a;
	cin>>b;
	NumOption(a, b);
	system("pause");
	return 0;
}


结果:
//输入
1

0
//输出

Exception!

关于异常处理有下面几点要注意:

1.在抛出一个异常之后,代码会转到异常处理的地方执行,throw后面的代码就不会再执行。如果没有找到相关catch,会跳出一级继续寻找。这个过程成为栈展开。所以要注意这样一种情况,在栈展开的过程中,程序块中的各种临时对象都会被销毁。析构函数作为释放资源的函数,如果发生了异常,要在函数内部catch,否则程序会terminate。
一个例子:
// ConsoleApplication3.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <vector>
#include <string>
using namespace std;

//异常类
class NumberException{};

//测试的类
class Test
{
public:
	~Test()
	{
		cout<<"Test is destructed!"<<endl;
	}
};

void NumOption(const int& a, const int& b)
{
	
	try
	{
		Test test;
		if (b == 0)
			throw NumberException();
		cout<<a / b<<endl;
	}
	catch(const NumberException& e)
	{
		cout<<"Exception!"<<endl;
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	
	int a,b;
	cin>>a;
	cin>>b;
	NumOption(a, b);

	system("pause");
	return 0;
}


正常情况:
//输入
1

1
//输出

1

Test is destructed!

异常情况:
//输入
1

0

//输出
Test is destructed!

Exception!

从上面的结果我们可以看出,正常情况下,程序执行完,先输出1,再销毁Test对象。但是抛出异常时,显然还没有出块的作用域,但是异常发生了,throw后面的内容不执行,也相当于声明周期结束,所有临时对象都会被销毁。

2.通常情况下,接受异常的catch块最好设定为引用类型。如果设为值传递,那么会发生基类参数接受子类异常时削去子类特有部分的情况。
并且我们可以设定是否为const引用,决定是否可以在catch块中对异常进行修改。

3.catch的匹配原则:越专门的匹配越靠前,换句话说,如果同时有子类和基类异常处理的catch,而抛出的是子类异常,我们为了能够处理子类,需要把子类异常处理放在前面。
例子:
// ConsoleApplication3.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <vector>
#include <string>
using namespace std;

//异常类
class NumberException{};
//派生的异常类
class ZeroException : public NumberException {};

void NumOption(const int& a, const int& b)
{
	
	try
	{
		if (b == 0)
			throw ZeroException();
		cout<<a / b<<endl;
	}

	catch(const ZeroException& e)
	{
		cout<<"ZeroException!"<<endl;
	}

	catch(const NumberException& e)
	{
		cout<<"NumberException!"<<endl;
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	
	int a,b;
	cin>>a;
	cin>>b;
	NumOption(a, b);

	system("pause");
	return 0;
}
结果:
1

0
//输出

ZeroException!

但是如果我们把catch(cost NumberException& e)和catch(const ZeroException& e)这两个换一下位置:结果就变成了
NumberException!

可见,要想处理更特例的异常,就要越放在前面。否则父类匹配了之后,不会再匹配子类。

4.重新抛出,当我们处理了一个异常但是没处理全时,可以将异常继续抛出。使用throw;关键字可以继续抛出。但是如果没有相应的catch继续接受异常的话,程序会terminate!
一个嵌套处理异常的例子:
// ConsoleApplication3.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <vector>
#include <string>
using namespace std;

//异常类
class NumberException{};
//派生的异常类
class ZeroException : public NumberException {};

void NumOption(const int& a, const int& b)
{
	try
	{
		if (b == 0)
			throw ZeroException();
		cout<<a / b<<endl;
	}

	catch(const ZeroException& e)
	{
		cout<<"ZeroException!"<<endl;
		throw;
	}

	catch (...)
	{
		cout<<"I can solve all Exception!"<<endl;
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	
	int a,b;
	cin>>a;
	cin>>b;
	//嵌套异常处理
	try
	{
		NumOption(a, b);
	}
	catch(const NumberException& e)
	{
		cout<<"NumberException!"<<endl;
	}

	system("pause");
	return 0;
}
结果:
1

0
//输出

ZeroException!

NumberException!

抛出异常时,先通过ZeroException异常处理,处理后继续抛出,外面的NumberException接收。

5.使用catch(...)可以捕获所有的异常:
catch (...)
	{
		cout<<"I can solve all Exceptions!"<<endl;
	}


6.为了加强程序的可读性,使函数的用户能够方便地知道所使用的函数会抛出哪些异常,可以在函数的声明中列出这个函数可能抛出的所有异常类型,例如:

void fun() throw( A,B,C,D);
这表明函数fun()可能并且只可能抛出类型(A,B,C,D)及其子类型的异常。

如果在函数的声明中没有包括异常的接口声明,则此函数可以抛出任何类型的异常,例如:

void fun();
一个不会抛出任何类型异常的函数可以进行如下形式的声明:

void fun() thow();
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: