【C++】异常处理(一)

这篇文章介绍下 C++ 的异常处理。

讨论一种最为常见的出现异常的情况,即 0 不能作为除数。为此,我们将自定义一个除法:

#include <iostream>

using namespace std;

int divide(int a, int b)
{
    return a / b;
}

int main()
{
    int a = 3, b = 0;
    int res = divide(a, b);
    cout << "result = " << res;
}

事实上这样的代码在我的电脑上运行会卡在终端,也没有提示无法运行的报错,把 res 直接改成 3/0 就看到正常的报错了:

TestDivide.cpp: In function 'int main()':
TestDivide.cpp:14:29: warning: division by zero [-Wdiv-by-zero]
   14 |     cout << "result = " << 2/0;
      |                            ~^~
result = 

不使用异常机制的处理

abort

尝试在函数内部加入针对除数为0的报错,使用 abort()

int divide(int a, int b)
{
    if(b==0)
    {
        cout << "cannot divide by 0" << endl;
        abort();
    }
    return a / b;
}

事实上,这次除了打印我加入的一行文字以外,程序的运行并没有明显的变化。abort() 的作用是向标准错误流发送消息 abnormal program termination ,然后终止程序。它还会返回一个值告诉父进程处理失败。

不知道为什么,这里没有终止进程。

返回值处理错误

另一种在 C++ 里常用的方式是,将我们想获取的值作为引用传回来,将返回值作为错误的标记。重新设计的 divide 如下:

bool divide(int a, int b, int& res)
{
    if(b==0)
    {
        cout << "cannot divide by zero" << endl;
        return false;
    }else
    {
        res = a/b;
        return true;   
    }
}

调用我就不写了。

这种方式一定程度上规避掉了系统的异常机制,换句话说,这是由开发者自己“实现”的异常,编译器不会认为这段代码是处理异常的。

使用异常机制的处理

现代C++ 的异常机制多少借鉴了其他语言的机制,即 throw-try-catch-finally 机制,即引发异常-捕获异常-处理异常

引发异常

改造 divide 函数,使其能够抛出异常:

int divide(int a, int b)
{
    if(b==0)
    {
        throw "cannot divide by ZERO!";
    }
    return a / b;
}

执行 throw 相当于返回了异常,因此从某种程度上来说,这里的 throwreturn 的作用差不多。但是不同的是,throw并不是把控制权返回给调用程序,而是会沿着调用序列后退,直到找到能处理异常的 catch 语句为止。

捕获与处理异常

main 函数改写如下:

int main()
{
    int a = 3, b = 0;
    int res = 0;
    try
    {
        res = divide(a, b);
    }
    catch (const char *s)
    {
        cout << s << endl;
    }

    cout << "res = " << res;
}

输出如下:

cannot divide by ZERO!
res = 0

如果引发的异常最终没有与之匹配的类型 catch,效果等同于调用 abort() 函数。

使用基于自定义类的异常机制

使用字符串处理异常需要我们编写代码打印异常类型,依据面向对象的原则,其实写一个类来处理更好。

在头文件中定义一个 bad_divide 类专门用于处理异常,其 what() 方法(此方法和 C++ 标准类中的方法在名字上是一致的)用于打印异常信息:

struct bad_divide
{
private:
    int a;
    int b;

public:
    bad_divide(int a, int b) : a(a), b(b){};
    void what()
    {
        cout << a << " divided by " << b << " is illegal!" << endl;
    }
};

同样,调用的地方也不再捕捉字符串了,而是捕捉这个对象,并调用 what() 方法打印异常。

int divide(int a, int b)
{
    if (b == 0)
    {
        throw bad_divide(a, b);
    }
    return a / b;
}
int main()
{
    int a = 3, b = 0;
    int res = 0;
    try
    {
        res = divide(a, b);
    }
    catch (bad_divide &bd)
    {
        bd.what();
    }

    cout << "res = " << res;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值