异常处理

异常

程序运行过程中,发生错误导致异常退出(不是程序的语法问题,而是代码的逻辑问题,编译不出错)。

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;
}

异常处理啊-LMLPHP

异常提供了一种转移权限控制权的方式。
程序一旦出现异常没有经过处理,就会造成程序运行的崩溃。
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:

#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;
}

异常处理啊-LMLPHP

try - catch

用于对 throw 抛出异常的捕获和处理。
try 中存放所有可能发生异常的语句,但 try 中只能捕获一次异常,当获取到一次异常后,后续的代码都不会执行。因此,建议在 try 中只存放一条语句。

验证异常对象 —> 补救措施
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;
}

异常处理啊-LMLPHP

#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 块可以匹配基类异常类型,提高匹配的成功率,但是会降低匹配的精度。
异常处理啊-LMLPHP

捕获标准类型的异常:

#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;
}

异常处理啊-LMLPHP

抛出自定义的异常:

#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;
}

异常处理啊-LMLPHP
异常处理啊-LMLPHP

12-02 11:42