16.1 异常的基本语法
- 1) 若有异常则通过throw操作创建一个异常对象并抛掷。
- 2) 将可能抛出异常的程序段嵌在try块之中。控制通过正常的顺序执行到达try语句,然后执行try块内的保护段。
- 3) 如果在保护段执行期间没有引起异常,那么跟在try块后的catch子句就不执行。程序从try块后跟随的最后一个catch子句后面的语句继续执行下去。
- 4) catch子句按其在try块后出现的顺序被检查。匹配的catch子句将捕获并处理异常(或继续抛掷异常)。
- 5) 如果匹配的处理器未找到,则运行函数terminate将被自动调用,其缺省功能是调用abort终止程序。
- 6)处理不了的异常,可以在catch的最后一个分支,使用throw语法,向上扔。
- 7)异常机制与函数机制互不干涉,但捕捉的方式是基于类型匹配。捕捉相当于函数返回类型的匹配,而不是函数参数的匹配,所以捕捉不用考虑一个抛掷中的多种数据类型匹配问题
- 8)异常捕捉严格按照类型匹配
完整示例代码:
#include <iostream>
using namespace std;
int Div(int x, int y)
{
if (0 == y)
{
//return -1;
//throw 0; //抛出异常
throw 'a';
}
return x / y;
}
int main()
{
int a, b;
cin >> a >> b;
try { //把可能抛出异常的代码放在try语句中
cout << Div(a, b) << endl;
}
catch(int) // throw 0;
{
cout << "zero exception" << endl;
}
catch(char) // throw 'a'
{
cout << "char exception" << endl;
}
return 0;
}
运行结果:
16.2 异常处理的基本思想
16.2.1 传统的错误处理机制:通过函数返回值处理错误
例如常见的:return -1;
16.2.2 异常处理思想
- 1)C++的异常处理机制使得异常的引发和异常的处理不必在同一个函数中,这样底层的函数可以着重解决具体问题,而不必过多的考虑异常的处理。上层调用者可以在适当的位置设计对不同类型异常的处理。
- 2)异常是专门针对抽象编程中的一系列错误处理的,C++中不能借助函数机制,因为栈结构的本质是先进后出,依次访问,无法进行跳跃,但错误处理的特征却是遇到错误信息就想要转到若干级之上进行重新尝试,如图
- 3)异常超脱于函数机制,决定了其对函数的跨越式回跳。
- 4)异常跨越函数
完整示例代码:
#include <iostream>
using namespace std;
int DDiv(int x, int y)
{
if (0 == y)
{
throw 0; // 可以跨越函数,不用在他的上一级语句判断函数返回值
}
return x / y;
}
int Div(int x, int y)
{
/*int ret = DDiv(x, y);
if (0 == ret)
{
}
else
{
}*/
return DDiv(x, y);
}
int main()
{
int a, b;
cin >> a >> b;
try{ //把可能抛出异常的代码放在try语句中
cout << Div(a, b) << endl;
}
catch(int)
{
cout << "zero exception" << endl;
}
catch (char)
{
cout << "char exception" << endl;
}
return 0;
}
运行结果:
16.3 异常接口声明
-
1)为了加强程序的可读性,可以在函数声明中列出可能抛出的所有异常类型,例如:
void func() throw (A, B, C , D);
//这个函数func()能够且只能抛出类型A B C D及其子类型的异常。 -
2)如果在函数声明中没有包含异常接口声明,则次函数可以抛掷任何类型的异常,例如:
void func();
-
3)一个不抛掷任何类型异常的函数可以声明为:
void func() throw();
-
4) 如果一个函数抛出了它的异常接口声明所不允许抛出的异常,unexpected函数会被调用,该函数默认行为调用terminate函数中止程序。
完整示例代码:
#include <iostream>
using namespace std;
int Div(int x, int y) throw(int, char); //只能抛出整形或者字符型异常
//int Div(int x, int y) throw(); //不会抛出任何类型异常
//int Div(int x, int y); //可能抛出任何类型的异常
int main()
{
int a, b;
cin >> a >> b;
try{ //把可能抛出异常的代码放在try语句中
cout << Div(a, b) << endl;
}
catch(int)
{
cout << "zero exception" << endl;
}
catch (char)
{
cout << "char exception" << endl;
}
return 0;
}
int Div(int x, int y) throw(int, char)
{
if (0 == y)
{
//return -1;
//throw 0; //抛出异常
throw 'a';
}
return x / y;
}
运行结果:
16.4 异常类型和异常变量的生命周期
16.4.1 传统处理错误
16.4.2 throw int类型异常
16.4.3 throw字符类型异常
16.4.4 throw类对象类型异常
完整示例代码:
#include <iostream>
using namespace std;
class Test
{
public:
Test()
{
cout << "Test构造函数" << endl;
}
Test(const Test &t)
{
cout << "Test拷贝构造函数" << endl;
}
void print()
{
cout << "Test Exceotion" << endl;
}
~Test()
{
cout << "Test析构函数" << endl;
}
};
int Div(int x, int y)
{
if (0 == y)
{
throw Test(); //抛出对象
//throw new Test; //抛出对象指针
}
return x / y;
}
int main()
{
int a, b;
cin >> a >> b;
try{ //把可能抛出异常的代码放在try语句中
cout << Div(a, b) << endl;
}
catch(int)
{
cout << "zero exception" << endl;
}
catch (char)
{
cout << "char exception" << endl;
}
/*catch (Test t) //调用拷贝构造函数
{
t.print();
}*/
catch (Test &t) //抛出对象,通过引用来接(推荐)
{
t.print();
}
catch (Test *t)
{
t->print();
delete t; //需要手动释放
}
return 0;
}
运行结果:
16.5 标准程序库异常
示例代码:
#include <iostream>
#include <exception>
using namespace std;
int main()
{
try{
int *p = new int[-1];
}
catch (exception &e)
{
cout << e.what() << endl;
}
return 0;
}
运行结果: