try 块和异常处理 (c++primer)

本文深入探讨了 C++ 中的异常处理机制,包括如何使用 throw 表达式引发异常,try 块如何捕获并处理这些异常,以及常见异常类如 runtime_error 的应用。通过具体实例,展示了如何在程序中有效地管理错误和异常情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

异常机制提供程序中错误检测与错误处理部分之间的通信。C++ 的异常处理中包括:

  1. throw 表达式,错误检测部分使用这种表达式来说明遇到了不可处理的错误。可以说,throw 引发了异常条件。

  2. try,错误处理部分使用它来处理异常。try 语句块以 try 关键字开始,并以一个或多个 catch 子句结束。在 try 块中执行的代码所抛出(throw)的异常,通常会被其中一个 catch 子句处理。由于它们“处理”异常,catch 子句也称为处理代码

  3. 由标准库定义的一组异常类,用来在 throw 和相应的 catch 之间传递有关的错误信息。


    throw 表达式

    回顾将两个 Sales_item 类型对象相加的程序,就是一个简单的例子。该程序检查读入的记录是否来自同一本书。如果不是,就输出一条信息然后退出程序。

         Sales_item item1, item2;
         std::cin >> item1 >> item2;
         // first check that item1 and item2 represent the same book
         if (item1.same_isbn(item2)) {
             std::cout << item1 + item2 << std::endl;
             return 0; // indicate success
         } else {
             std::cerr << "Data must refer to same ISBN"
                       << std::endl;
             return -1; // indicate failure
         }
    

    在使用 Sales_items 的更简单的程序中,把将对象相加的部分和负责跟用户交互的部分分开。在这个例子中,用 throw 抛出异常来改写检测代码:

         // first check that data is for the same item
         if (!item1.same_isbn(item2))
             throw runtime_error("Data must refer to same ISBN");
         // ok, if we're still here the ISBNs are the same
         std::cout << item1 + item2 << std::endl;
    

    这段代码检查 ISBN 对象是否不相同。如果不同的话,停止程序的执行,并将控制转移给处理这种错误的处理代码。

    throw 语句使用了一个表达式。在本例中,该表达式是 runtime_error 类型的对象。runtime_error 类型是标准库异常类中的一种,在 stdexcept 头文件中定义。在后续章节中很快就会更详细地介绍这些类型。我们通过传递 string 对象来创建 runtime_error 对象,这样就可以提供更多关于所出现问题的相关信息。

    try

    try 块的通用语法形式是:

         try {
             program-statements
         } catch (exception-specifier) {
             handler-statements
         } catch (exception-specifier) {
             handler-statements
         } //...
    

    try 块以关键字 try 开始,后面是用花括号起来的语句序列块。try 块后面是一个或多个 catch 子句。每个 catch 子句包括三部分:关键字 catch,圆括号内单个类型或者单个对象的声明——称为异常说明符,以及通常用花括号括起来的语句块。如果选择了一个 catch 子句来处理异常,则执行相关的块语句。一旦 catch 子句执行结束,程序流程立即继续执行紧随着最后一个 catch 子句的语句。

    try 语句内的 program-statements 形成程序的正常逻辑。这里面可以包含任意 C++ 语句,包括变量声明。与其他块语句一样,try 块引入局部作用域,在 try 块中声明的变量,包括 catch 子句声明的变量,不能在 try 外面引用。

    在前面的例子中,使用了 throw 来避免将两个表示不同书的 Sales_items 对象相加。想象一下将 Sales_items 对象相加的那部分程序与负责与用户交流的那部分是分开的,则与用户交互的部分也许会包含下面的用于处理所捕获异常的代码:

         while (cin >> item1 >> item2) {
             try {
                 // execute code that will add the two Sales_items
                 // if the addition fails, the code throws a runtime_error exception
             } catch (runtime_error err) {
                 // remind the user that ISBN must match and prompt for another pair
                 cout << err.what()
                      << "\nTry Again? Enter y or n" << endl;
                 char c;
                 cin >> c;
                 if (cin && c == 'n')
                     break;     // break out of the while loop
             }
         }
    

    关键字 try 后面是一个块语句。这个块语句调用处理 Sales_item 对象的程序部分。这部分也可能会抛出 runtime_error 类型的异常。

    上述 try 块提供单个 catch 子句,用来处理 runtime_error 类型的异常。在执行 try 块代码的过程中,如果在 try 块中的代码抛出 runtime_error 类型的异常,则处理这类异常的动作在 catch 后面的块语句中定义。本例中,catch 输出信息并且询问用户是否继续进行异常处理。如果用户输入'n',则结束 while;否则继续循环,读入两个新的 Sales_items 对象。

    通过输出 err.what() 的返回值提示用户。大家都知道 err 返回 runtime_error 类型的值,因此可以推断出 whatruntime_error 类的一个成员函数(1.5.2 节)。每一个标准库异常类都定义了名为 what 的成员函数。这个函数不需要参数,返回 C 风格字符串。在出现 runtime_error 的情况下,what 返回的 C 风格字符串,是用于初始化 runtime_errorstring 对象的副本。如果在前面章节描述的代码抛出异常,那么执行这个 catch 将输出。

         Data must refer to same ISBN
         Try Again? Enter y or n
    


    1. <stdexcept> 头文件中定义的标准异常类

      exception

      最常见的问题。

      runtime_error

      运行时错误:仅在运行时才能检测到问题

      range_error

      运行时错误:生成的结果超出了有意义的值域范围

      overflow_error

      运行时错误:计算上溢

      underflow_error

      运行时错误:计算下溢

      logic_error

      逻辑错误:可在运行前检测到问题

      domain_error

      逻辑错误:参数的结果值不存在

      invalid_argument

      逻辑错误:不合适的参数

      length_error

      逻辑错误:试图生成一个超出该类型最大长度的对象

      out_of_range

      逻辑错误:使用一个超出有效范围的值


    new头文件定义了 bad_alloc 异常类型,提供因无法分配内在而由 new抛出的异常。

    type_info 头文件定义了 bad_cast 异常类型。


    标准库异常类

    标准库异常类只提供很少的操作,包括创建、复制异常类型对象以及异常类型对象的赋值。 exceptionbad_alloc 以及 bad_cast 类型只定义了默认构造函数,无法在创建这些类型的对象时为它们提供初值。其他的异常类型则只定义了一个使用 string 初始化式的构造函数。当需要定义这些异常类型的对象时,必须提供一想 string 参数。string 初始化式用于为所发生的错误提供更多的信息。

    异常类型只定义了一个名为 what 的操作。这个函数不需要任何参数,并且返回 const char* 类型值。它返回的指针指向一个 C 风格字符串。使用 C 风格字符串的目的是为所抛出的异常提出更详细的文字描述。

    what 函数所返回的指针指向 C 风格字符数组的内容,这个数组的内容依赖于异常对象的类型。对于接受 string 初始化式的异常类型,what 函数将返回该 string 作为 C 风格字符数组。对于其他异常类型,返回的值则根据编译器的变化而不同。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值