C++异常处理

C++ 的异常处理中包括:


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


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


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




throw表达式:


      系统通过 throw 表达式抛出异常。throw 表达式由关键字 throw 以及尾随的表达式组成,通常以分号结束,这样它就成为了表达式语句。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 类型的值,因此可以推断出 what 是 runtime_error 类的一个成员函数(1.5.2 节)。每一个标准库异常类都定义了名为 what 的成员函数。这个函数不需要参数,返回 C 风格字符串。在出现 runtime_error 的情况下,what 返回的 C 风格字符串,是用于初始化 runtime_error 的 string 对象的副本。如果在前面章节描述的代码抛出异常,那么执行这个 catch 将输出。


       在复杂的系统中,程序的执行路径也许在遇到抛出异常的代码之前,就已经经过了多个 try 块。例如,一个 try 块可能调用了包含另一 try 块的函数,它的 try 块又调用了含有 try 块的另一个函数,如此类推。


          寻找处理代码的过程与函数调用链刚好相反。抛出一个异常时,首先要搜索的是抛出异常的函数。如果没有找到匹配的 catch,则终止这个函数的执行,并在调用这个函数的函数中寻找相配的 catch。如果仍然找到相应的处理代码,该函数同样要终止,搜索调用它的函数。如此类推,继续按执行路径回退,直到找到适当类型的 catch 为止。


        如果不存在处理该异常的 catch 子句,程序的运行就要跳转到名为 terminate 的标准库函数,该函数在 exception 头文件中定义。这个标准库函数的行为依赖于系统,通常情况下,它的执行将导致程序非正常退出。


        在程序中出现的异常,如果没有经 try 块定义,则都以相同的方式来处理:毕竟,如果没有任何 try 块,也就没有捕获异常的处理代码(catch 子句)。此时,如果发生了异常,系统将自动调用 terminate 终止程序的执行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值