异常处理
异常
程序运行过程中,发生错误导致异常退出(不是程序的语法问题,而是代码的逻辑问题,编译不出错)。
e.g. string 字符串,使用 at 函数访问其中的字符元素时,如果越界,程序会抛出:out_of_range
只要抛出异常,且不对异常进行处理,后面代码都将不会执行。
#include <iostream>
using namespace std;
int main()
{
string str = "Hey!";
cout << str.at(6) << endl;
cout << "Hello~" << endl;
return 0;
}
异常提供了一种转移权限控制权的方式。
程序一旦出现异常没有经过处理,就会造成程序运行的崩溃。
C++ 中提供了异常处理的机制。需要两种配合使用:抛出异常(throw)和 捕获异常(try-catch)
throw
thorw 语句的操作数可以是任意的表达式,表达式的结果的类型决定了抛出异常的类型。
抛出到函数调用的上一级。
// 无效的 throw:
#include <iostream>
using namespace std;
int divide(int a, int b)
{
int c = a/b; // 可疑代码
if (b == 0) // 抛出异常
throw int(0);
return c;
}
int main()
{
cout << divide(3, 0) << endl;
cout << "Hello~" << endl;
return 0;
}
一定要先抛出异常,再执行可疑代码。
Throw 只能抛出异常,不能对异常进行处理(不会让异常发生,但是代码仍然不能继续执行)。
throw 数据类型(值);
// 有效的 throw:
#include <iostream>
using namespace std;
int divide(int a, int b)
{
if (b == 0)
throw int(0); // 抛出到函数调用的上一级
return a/b;
}
int main()
{
cout << divide(3, 0) << endl;
cout << "Hello~" << endl;
return 0;
}
try - catch
用于对 throw 抛出异常的捕获和处理。
try 中存放所有可能发生异常的语句,但 try 中只能捕获一次异常,当获取到一次异常后,后续的代码都不会执行。因此,建议在 try 中只存放一条语句。
catch 对异常进行处理:
验证异常对象 —> 补救措施
1、按异常的类型处理,catch(类型) —> 根据不同的类型,输出不同处理
2、对异常值进行处理,catch(类型 值) —> 根据不同的值,输出不同处理
#include <iostream>
using namespace std;
void search(int *arr, int size, int index)
{
if (index < 0)
{
throw string("Negative index");
}
if (index == size)
{
throw int(size);
}
if (index > size)
{
throw int(index);
}
cout << "array[" << index << "] = " << *(arr + index) << endl;
}
int main()
{
int array[3] = {1, 2, 3};
try {
search(array, 3, 2);
search(array, 3, -1);
} catch (string) {
cout << "Error: Negative index" << endl;
} catch (int num) {
if (num == 3)
cout << "Error: Index equals to size" << endl;
if (num > 3)
cout << "Error: Index greater than size" << endl;
}
try {
search(array, 3, 3);
} catch (string) {
cout << "Error: Negative index" << endl;
} catch (int num) {
if (num == 3)
cout << "Error: Index equals to size" << endl;
if (num > 3)
cout << "Error: Index greater than size" << endl;
}
try {
search(array, 3, 5);
} catch (string) {
cout << "Error: Negative index" << endl;
} catch (int num) {
if (num == 3)
cout << "Error: Index equals to size" << endl;
if (num > 3)
cout << "Error: Index greater than size" << endl;
}
cout << "Hello~" << endl;
return 0;
}
#include <iostream>
using namespace std;
double division(double a, double b)
{
if (b == 0)
{
string text("除数等于0!");
throw text; // 抛出一个异常:std::string
}
return a/b;
}
double input()
{
cout << "input 开始执行 " << endl;
double a;
double b;
cout << "请输入两个浮点型:"<< endl;
cin >> a >> b;
double c = 0;
try
{
c = division(a, b);
}catch(string &e)
{
// 验证异常对象
cout << e << endl;
// 补救措施
return 0;
}
cout << "input 执行结束" << endl;
return c;
}
int main()
{
cout << "main函数开始执行" <<endl;
cout << input() << endl;
cout << "程序执行结束" <<endl;
return 0;
}
捕获异常可能会出现以下几种情况:
1、 无异常抛出,此时程序正常运行,不进入 catch 块。
2、 异常抛出,正确捕获,此时程序进入 catch 块。
3、 异常抛出,错误捕获(捕获类型不对),此时程序仍然会向上抛出寻求正确捕获,如果每一层都没有正确捕获,程序仍然停止运行。
注意:
1、抛出异常一定要在发生异常之前;
2、抛出异常时,一定要给出数据类型和值;
3、try - catch 对异常处理时分为两种情况:
a. 同类型的异常只有一个,在 catch 中可以直接对异常类型进行判断;
b. 如果相同类型的异常有多个,需要对异常值进行判断。
标准异常体系
C++ 将常见的的异常类型进行了定义和分类,引入:#include<stdexcept> 头文件后可使用。
但是这个体系还是太薄弱,可以对其进行拓展。
catch 块可以匹配基类异常类型,提高匹配的成功率,但是会降低匹配的精度。
捕获标准类型的异常:
#include <iostream>
#include <stdexcept> // 头文件
using namespace std;
int main()
{
string s = "Hello, world";
cout << s[12] << endl; // 打印空行的'\0',这就是建议使用 at()函数 的原因
try // 尝试抛出一个异常
{
cout << s.at(100) << endl;
}catch(out_of_range &e)
{
// 输出错误信息
cout << e.what() << endl;
// 弥补措施
cout << "-1" << endl;
}
return 0;
}
抛出自定义的异常:
#include <iostream>
#include <stdexcept> // 头文件
using namespace std;
// 继承exception
class MyException:public exception
{
public:
// 覆盖 what 函数
// throw:异常规格说明
// 表示此函数不会出现异常的抛出
const char * what() const throw()
{
return "Customized";
}
};
void show(string a, string b)
{
if (a == "#" || b == "#")
{
throw MyException();
cout << a << b << endl; // 此句永远不会被执行
}
}
int main()
{
cout << "Please input two strings: " << endl;
string a;
string b;
cin >> a >> b;
try
{
show(a, b);
}catch(MyException &e)
{
cout << e.what() <<endl;
}
cout << "End. " << endl;
return 0;
}