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

上面的代码运行到第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;
}

异常捕获 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;
}

自定义异常

上面的代码中,手动抛出的异常类型是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;
}

之所以要自定义异常类型,并继承自标准异常,是因为异常的捕获不光可以匹配精准的类型,也可以匹配粗略的类型(基类)。
异常捕获也支持多重捕获,类似于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;
}

try-catch块的执行逻辑是:

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

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值