C++异常抛出机制:throw和try_catch

文章目录

  • 前言
  • 正文
    • 初识throw和try_catch
    • 深入(std::runtime_error和std::exception)
    • 异常处理的必要性

前言

还记得初学C++的时候,我抱着《C++ primer 5th》这本书硬啃,作为一个初学者,里面很多东西当时都很不理解,其中就包括了try_catch和throw这一块,我觉得那本书真的不适合新手入门,在一开始看到异常处理类:std::runtime_error的时候,我感觉我小脑萎缩了,因为这个东西好像前面的内容都没有提及过?看也看不懂,很是痛苦。时隔一年,终于在《C++参考手册》的帮助下搞懂了这个开发必备知识点

正文

初识throw和try_catch

首先,我们需要知道什么是throw和try_catch(异常处理机制):

try_catch是一种异常处理机制,用于捕获和处理异常。异常是在程序执行期间发生的错误或意外情况,它打断了正常的程序流程,并且可能导致程序崩溃或未定义的行为。

这里给出一段示例代码吧,我们对这段示例代码进行一个分析:

#include 
#include 

void divideNumbers(int x, int y) {
    if (y == 0) {
        throw std::runtime_error("Error: Divide by zero!");
    }
    std::cout << "Result: " << x / y << std::endl;
}

int main() {
    try {
        divideNumbers(10, 0);
    } catch (const std::runtime_error& ex) {
        std::cout << "Caught exception: " << ex.what() << std::endl;
    }
    
    return 0;
}

这是一段除法计算的简单代码。我们都知道:除数不能为0,因此,在这里我们就进行一个异常检测:若是检测到除数为0,就使用throw语句抛出异常。我们来看看这段程序的执行结果:

Caught exception: Error: Divide by zero!

throw语句我认为可以理解为类似于函数的返回值,虽然这么说有点不恰当,但是我还是说说我这么认为的理由:

  1. 在throw抛出异常之后,try_catch语句的执行权就发生了更改:原本是执行try中的语句,现在转为执行catch中的语句,而try中未执行的语句不再执行
  2. 抛出的异常类似于函数的返回值,catch捕获throw的抛出的异常。

通过上面这段简短的程序,我们应该已经对throw和try_catch语句有了一个初步的了解。

深入(std::runtime_error和std::exception)

在上面那段程序中我们能够发现两个我们之前未曾见过的类:std::runtime_error和std::exception,它们都在头文件stdexcept和命名空间std中。
我们先说std::runtime_error吧,从它的名字我们就能够理解它的作用:run_time_error(程序运行时出错),它是C++提供的异常类,用于:运行时抛出错误的情况下创建异常对象。std::runtime_error的构造函数接收一个参数:一个字符串或者一个C风格的数组

namespace std {
  class runtime_error : public exception {
  public:
    explicit runtime_error(const string& what_arg);

    explicit runtime_error(const char* what_arg);

    const char* what() const noexcept override;

    runtime_error(const runtime_error&) = default;
    runtime_error& operator=(const runtime_error&) = default;
    runtime_error(runtime_error&&) = default;
    runtime_error& operator=(runtime_error&&) = default;
    ~runtime_error() override;
  };
}

这个参数用于:描述异常的错误信息。同时我们还能看到:它继承自std::exception,并重写了虚函数what(),这个函数用于返回异常的描述信息,也就是先前传入构造函数的参数。

std::runtime_error的内容就差不多讲完了,我们接下来说它的基类:std::exception,它才是异常处理类的核心。

C++提供了很多异常处理类,但是所有的异常处理类都有一个共同的基类:std::expection

namespace std {
  class exception {
  public:
    exception() noexcept;
    exception(const exception&) noexcept;
    exception& operator=(const exception&) noexcept;
    virtual ~exception();

    virtual const char* what() const noexcept;
  };
}

可以看到,相比起std::runtime_error,它的东西就很少了,它的存在主要是为了方便其他的异常处理类,而在上面的例子中,我们的catch就是将throw抛出的异常std::runtime_error捕获后“向上转型”为它的基类std::exception(“向上转型”是C++多态的一个十分重要的特性,我会在后续的文章中进行详细的说明),之后,基类调用what()函数,从而完成了对异常的打印操作。

异常处理的必要性

在大型程序中,我们往往不能够及时发现程序的bug在哪,但是我们可以大概感觉到哪里可能出问题,因此我们就能够使用throw和try_catch在程序运行时对异常进行处理。这样做不仅能够帮助我们找到异常出现的原因,同时不会影响程序的正常运行

你可能感兴趣的:(玩转C++,C++,初学者,c++)