当前位置:   article > 正文

[C++] 十 异常处理-抛出与捕获_c++抛出异常

c++抛出异常

异常的概念

异常是程序在 运行期间 产生的问题,程序可以正常通过编译,没有语法问题,只是由于在运行中触发了一些C++预定义的逻辑问题,从而产生了异常现象。异常是需要正确的处理的,如果没有得到正确处理,则程序运行会终止

处理异常的两种方式:

●抛出异常 throw
●捕获异常 try-catch

抛出异常 throw

C++底层和程序员都可以抛出异常,例如在下面的代码中,C++底层会抛出一个异常对象,这个异常对象会优先在当前代码寻找处理的措施,当找不到时,会向上转移,直到找到处理的措施,一直向上转移到主函数还找不到处理措施就会运行终止

#include <iostream>

using namespace std;

void test1()
{
    string s = "23";
    cout << s.at(34) << endl; // 抛出异常对象
}

void test2()
{
    test1();
}


int main()
{
    test2();

    cout << "主函数执行结束" << endl;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

上面的代码运行到第8行,C++底层检测到下标范围越界,会抛出一个异常对象,这个对象首先在第8行寻找处理措施的相关代码,找不到就去上一级第13行寻找,找不到再去第19行寻找,直到主函数还是没有处理这个异常,于是程序运行终止,并输出异常对象携带的相关信息。
除了C++底层固定的一些错误的逻辑操作会抛出异常外,程序员也可以自己制定抛出的时机和抛出的异常对象。因为C++的异常体系不是特别健全,因此如果要在项目中使用异常处理,程序员自身规定一些逻辑错误的情况,并抛出对应的异常对象就显得相对重要了

#include <iostream>

using namespace std;

double division(double a,double b)
{
    // 手动抛出异常对象
    if(b == 0)
        throw "不能除以0!!!!";
    return a/b;
}

int main()
{
    double d = division(3,0);
    cout << d << endl;

    cout << "主函数执行结束" << endl;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

异常捕获 try-catch

把可能出现异常的代码放置到try代码块中,在catch代码块中编写对应的处理逻辑。try块中尽量少放代码,非异常代码在try中虽然也可以得到正常执行的,但是效率偏低。
try块必须配合catch块进行异常类型匹配。需要注意的是,catch块如果匹配的类型不一致,整个异常捕获都会失效

#include <iostream>

using namespace std;

double division(double a,double b)
{
    // 手动抛出异常对象
    if(b == 0)
        throw "不能除以0!!!!";
    return a/b;
}

int main()
{
    try
    {
        double d = division(3,0);
        cout << d << endl;
    }
	catch(const char* e)
    {
        cout << e << endl;
        cout << 1 << endl; // 弥补措施
    }

    cout << "主函数执行结束" << endl;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

自定义异常

上面的代码中,手动抛出的异常类型是char*,这种类型不是推荐的异常类型,一个标准的类型应该从继承结构上属于标准异常家族。
以下是C++标准异常库的相关类型:


使用上面的异常类型需要引入头文件 #include stdexcept(尖括号在scdn文档中会隐藏掉括号中的内容)
标准异常库的类型相对较少,无法覆盖很多开发的情况,程序员可以自定义一个异常类继承标准异常库中异常类型

#include <iostream>
#include <stdexcept>

using namespace std;

class ZeroException:public exception
{
public:
    // 覆盖what函数
    const char* what() const throw()
    {
        return "不能除以0!!!!";
    }
};


double division(double a,double b)
{
    // 手动抛出异常对象
    if(b == 0)
        throw ZeroException();
    return a/b;
}

int main()
{
    try
    {
        double d = division(3,0);
        cout << d << endl;
    }catch(const ZeroException& e)
    {
        cout << e.what() << endl; // 打印异常信息
        cout << 1 << endl; // 弥补措施
    }

    cout << "主函数执行结束" << endl;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

之所以要自定义异常类型,并继承自标准异常,是因为异常的捕获不光可以匹配精准的类型,也可以匹配粗略的类型(基类)。
异常捕获也支持多重捕获,类似于switch-case,case语句可以若干个,catch语句也可以有若干个。如果使用多重捕获,一定要先捕获派生类异常类型,再捕获基类异常类型,可以认为基类异常类型是一种保底的措施

#include <iostream>
#include <stdexcept>

using namespace std;

class ZeroException:public exception
{
public:
    // 覆盖what函数
    const char* what() const throw()
    {
        return "不能除以0!!!!";
    }
};


double division(double a,double b)
{
    // 手动抛出异常对象
    if(b == 0)
        throw ZeroException();
    return a/b;
}

int main()
{
    try
    {
        double d = division(3,0);
        cout << d << endl;
    }catch(ZeroException e)
    {
        cout << e.what() << endl; // 打印异常信息
        cout << 2 << endl; // 弥补措施
    }catch(exception e)
    {
        cout << e.what() << endl; // 打印异常信息
        cout << 1 << endl; // 弥补措施
    }

    cout << "主函数执行结束" << endl;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

try-catch块的执行逻辑是:

另外,可以使用…匹配任意异常类型,包括非标准异常库类型

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/715015
推荐阅读
相关标签
  

闽ICP备14008679号