小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
一、异常处理机制
1.1 相关概念
面向对象一般都有异常处理机制,异常处理就是处理程序中的错误。所谓错误是指在程序运行的过程中发生的一些异常事件(如:除0溢出,数组下标越界,所要读取的文件不存在,空指针,内存不足等等)。
1.2 语法格式
检测异常:try
语句块,将还有抛出异常的代码放在try
语句块中进行检测
try{
}
抛出异常:throw
关键字,当执行了throw
之后,try
语句块就会立即结束,运行后面处理异常的代码
throw 常量/表达式/变量
处理异常:catch
函数,当抛出异常之后,立即执行当前函数内部的代码,catch
函数参数的类型要与throw
抛出的类型一致
catch(执行类型的引用)
{
}
1.3 用户自定义异常
#include <iostream>
using namespace std;
int MyDiv1(int m, int n)
{
if(n == 0)
{ //C语言中没有异常处理机制,所以返回-1表示出错
return -1;
}
else
{
return m / n;
}
}
void test1()
{
//int num = MyDiv2(10, 3);
//int num = MyDiv2(10, 0);
int num = MyDiv1(10, -10);
if(num == -1)
{
cout << "出错:除数为0" << endl;
}
else
{
cout << num << endl;
}
}
//异常处理机制的简单使用
void test2()
{
cout << "11111111111111111" << endl;
try {
cout << "hello world" << endl;
//含有throw的代码要放在try当中,可以是代码也可以是函数
//当执行到throw,try语句块就会立即结束执行catch里面的代码
throw 10.345f;
cout << "nihao beijing" << endl;
}
//try后面必须紧跟catch,否则报错
//cout << "***************" << endl;
//catch函数的参数类型要与throw抛出的值的类型一致
catch (float &e) {
cout << "111welcome to hqyj:" << e << endl;
}
catch (int &e) {
cout << "222welcome to hqyj:" << e << endl;
}
cout << "22222222222222222" << endl;
}
//用户自定义异常
//当自己封装函数时,如果出现了异常,只抛出异常,
//而检测和处理异常的代码不在函数内部写,而是在调
//用的时候再去写
int MyDiv2(int m, int n)
{
if(n == 0)
{
throw -1;
}
else
{
return m / n;
}
}
void test3()
{
int a = 10, b = 0;
int num;
try {
num = MyDiv2(a, b);
cout << a << "/" << b << "=" <<num << endl;
} catch (int &e) {
cout << "错误:除数为0" << endl;
}
}
int main()
{
test3();
return 0;
}
练习:编写函数,获取数组指定元素的内容
#include <iostream>
using namespace std;
int getArray(int *a, int len, int n)
{
if(n < 0 || n > len - 1)
{
throw 0;
}
else
{
return a[n];
}
}
void test1()
{
int arr[] = {100, 20, 5, 33, 89, 66, 91, 73, 52};
int num;
try {
num = getArray(arr, sizeof(arr) / sizeof(int), 20);
cout << num << endl;
} catch (int &e) {
if(e == 0)
{
cout << "数组元素访问越界" << endl;
}
}
}
int main()
{
test1();
return 0;
}
1.4 标准异常库
标准库中也提供了很多的异常类,它们是通过类继承组织起来的。异常类继承层级结构图如下:
标准异常类的具体描述:
异常名称 | 描述 |
---|---|
exception | 所有标准异常类的父类 |
bad_alloc | 当operator new and operator new[],请求分配内存失败时 |
bad_exception | 这是个特殊的异常,如果函数的异常抛出列表里声明了bad_exception异常,当函数内部抛出了异常抛出列表中没有的异常,这是调用的unexpected函数中若抛出异常,不论什么类型,都会被替换为bad_exception类型 |
bad_typeid | 使用typeid操作符,操作一个NULL指针,而该指针是带有虚函数的类,这时抛出bad_typeid异常 |
bad_cast | 使用dynamic_cast转换引用失败的时候 |
ios_base::failure | io操作过程出现错误 |
logic_error | 逻辑错误,可以在运行前检测的错误 |
runtime_error | 运行时错误,仅在运行时才可以检测的错误 |
logic_error的子类:
异常名称 | 描述 |
---|---|
length_error | 试图生成一个超出该类型最大长度的对象时,例如vector的resize操作 |
domain_error | 参数的值域错误,主要用在数学函数中。例如使用一个负值调用只能操作非负数的函数 |
out_of_range | 超出有效范围 |
invalid_argument | 参数不合适。在标准库中,当利用string对象构造bitset时,而string中的字符不是’0’或’1’的时候,抛出该异常 |
runtime_error的子类:
异常名称 | 描述 |
---|---|
range_error | 计算结果超出了有意义的值域范围 |
overflow_error | 算术计算上溢 |
underflow_error | 算术计算下溢 |
invalid_argument | 参数不合适。在标准库中,当利用string对象构造bitset时,而string中的字符不是’0’或’1’的时候,抛出该异常 |
#include <iostream>
#include <exception>
using namespace std;
int getArray(int *a, int len, int n)
{
if(n < 0 || n > len - 1)
{
//out_of_range oor("数组元素访问越界");
//throw oor;
//可以使用匿名对象来返回
throw out_of_range("数组元素访问越界");
}
else
{
return a[n];
}
}
void test1()
{
int arr[] = {100, 20, 5, 33, 89, 66, 91, 73, 52};
int num;
try {
num = getArray(arr, sizeof(arr) / sizeof(int), 20);
cout << num << endl;
}
//当使用标准异常库时,如果不知道是哪个类,可以使用所有标准异常类的父类
catch (exception &e) {
cout << e.what() << endl;
}
}
int main()
{
test1();
return 0;
}