📜  C++ |异常处理问题12(1)

📅  最后修改于: 2023-12-03 15:29:51.935000             🧑  作者: Mango

C++ | 异常处理问题12

在 C++ 中,异常处理是一种处理程序出现异常情况的机制。当程序执行时遇到错误,会抛出异常,并中断当前执行流程,转而去执行异常处理机制。在异常处理机制中,程序会尝试恢复异常情况,或者在无法恢复时向外界报告错误。异常处理机制是一种保证程序运行安全的重要方式。

然而,在使用异常处理机制时,也可能会遇到一些问题。本文将介绍一个针对异常处理的问题,以及如何解决这个问题。

问题描述

假设有以下 C++ 代码:

int foo(int a, int b) {
    if (b == 0) {
        throw "divided by zero";
    }
    return a / b;
}

int main() {
    int a = 4, b = 0;
    try {
        int res = foo(a, b);
        std::cout << res << std::endl;
    } catch(const char* err) {
        std::cerr << err << std::endl;
    }
    return 0;
}

这段代码的逻辑非常简单,我们定义了一个 foo 函数,该函数的作用是计算两个整数的商,当第二个整数为0时,程序将抛出一个带有错误信息的字符串类型异常。在 main 函数中,我们进行了异常处理,如果异常被抛出,我们会将错误信息打印到标准错误流中。

这段代码看起来没什么问题,但是当我们把它编译运行后,发现程序并没有像我们预期的那样输出 divided by zero,而是输出了一段神秘的东西:

libc++abi.dylib: terminating with uncaught exception of type char const*
Abort trap: 6

这是什么原因呢?

问题分析

首先,我们需要了解一下 libc++abi 是什么。在 Mac OS X 中,C++ 程序的异常处理机制是由 libc++abi 库实现的。当程序抛出异常时,会调用 __cxa_throw 函数,该函数属于 libc++abi 库。这个函数负责将异常对象抛出并执行异常处理机制。当没有对异常进行处理时,程序就会崩溃。

回到我们之前的代码,当程序执行到 throw "divided by zero"; 这一行时,程序抛出了一个 const char* 类型的异常。但是,这种异常类型并不是 C++ 标准库中提供的异常类型,也就是说这种异常类型不是标准 C++ 异常,它是由操作系统提供的。因此,当 __cxa_throw 函数尝试捕获这个异常时,它无法识别这个异常对象,于是程序就崩溃了。

解决方案

我们知道了问题的来源,我们该怎么解决呢?解决方法其实很简单,只需要将异常类型改为标准 C++ 异常类型即可。在 C++ 中,标准异常类是 std::exception,它是一个抽象基类,不提供具体的实现,只定义了一个纯虚函数 what,用于返回异常的错误信息。我们可以继承这个基类,实现我们自己的异常类。

修改后的代码如下:

class DivideByZeroException: public std::exception {
public:
    virtual const char* what() const throw() {
        return "divided by zero";
    }
};

int foo(int a, int b) {
    if (b == 0) {
        throw DivideByZeroException();
    }
    return a / b;
}

int main() {
    int a = 4, b = 0;
    try {
        int res = foo(a, b);
        std::cout << res << std::endl;
    } catch(const std::exception& err) {
        std::cerr << err.what() << std::endl;
    }
    return 0;
}

我们定义了一个名为 DivideByZeroException 的类,继承了 std::exception 类,并且实现了 what 函数,返回了一个字符串类型的错误信息。在 foo 函数中,我们抛出了一个 DivideByZeroException 类型的异常。在 main 函数中,我们进行了异常处理,当遇到异常时,我们打印了错误信息。

这个修改后的代码运行结果如下:

divided by zero

可以看到,我们已经成功解决了这个问题。

总结

本文介绍了一个针对 C++ 异常处理的问题,以及如何解决这个问题。异常处理机制是 C++ 程序中必不可少的一部分,要想写出高质量的程序,我们必须掌握好异常处理的知识。