• 异常处理


    一、关键点

    异常:存在于运行时的反常行为,这些行为超出了函数正常功能的范围。

    典型的异常:失去数据库连接、遇到意外输入等。

    异常处理机制:为程序中异常检测异常处理这两部分的协作提供支持。

    二、异常检测

    形式:throw 表达式;

    解释:上面的语句将引发(或抛出)一个异常,其中表达式的类型就是抛出的异常类型

    示例:throw runtime_error("自定义提示语");    //类型runtime_error就是一种异常类型

    类型runtime_error:是标准库异常类型中的一种,定义在stdexcept头文件中。我们必须初始化runtime_error的对象,方式是给它提供一个string对象或一个字符串字面值,这个字符串主要写一些关于异常的辅助信息。

    ————————————————2017-11-7更新补充————————————————

    补充1:表达式不仅仅只有一个异常类型(也就是抛出对象的类型),还包括抛出对象的内容,如throw runtime_error("除数不能为0"),其中标红的地方就是抛出对象的内容。

    补充2:throw语句执行完,就转到对应的catch语句,而非继续执行throw语句之后的语句。

    补充3:异常对象,编译器使用异常抛出表达式来对异常对象进行拷贝初始化(这是另一种抛出异常的形式:range_error r("errpr"); throw r;)

    补充4:当异常处理完毕后,异常对象被销毁(因此,如果异常抛出表达式是类类型的话,则相应的类必须含有一个可访问的析构函数)

    ——————————————————补充完毕———————————————————

    三、异常处理

    1. try语句块

    语法形式:

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

    解释:try语句块中的program-statements组成程序的正常逻辑,像其他任何块一样,program-statements可以有包含声明在内的任意C++语句。只是在try语句块内声明的变量在块外无法访问,即使是catch子句也无法访问。

    2. catch子句

    包括三部分:关键字catch、括号内一个(可能未命名的)对象的声明(称作异常声明)、一个语句块

    多个catch子句:当选中了某个catch子句处理异常之后,执行与之对应的块。

    catch子句完成:程序跳转到最后一个catch子句之后的那条语句继续执行。

    ————————————————2017-11-7更新补充————————————————

    补充1:若找到一个匹配的catch子句,则程序进入该子句并执行其中的代码

    补充2:当执行完这个catch子句后,找到与try块关联的最后一个catch子句之后的点,并从这里继续执行

    补充3:异常声明的类型决定了处理代码所能捕获的异常类型

    补充4:进入一个catch语句后,通过异常对象初始化异常声明中的参数

    补充5:异常的类型和catch声明的类型的匹配规则:①允许从非常量向常量的类型转换,即一个非常量对象的throw语句可以匹配一个接受常量引用的catch语句;②允许从派生类向基类的类型转换;③数组被转换成指向数组(元素)类型的指针,函数被转换成指向该函数类型的指针

    补充6:捕获所有异常的catch语句,形如catch(...),可以与任意类型的异常匹配

    ——————————————————补充完毕———————————————————

    四、寻找处理代码的辛酸过程

    1. try语句块可能调用了包含另一个try语句块的函数:使得程序在遇到抛出异常的代码前,其执行路径可能已经经过了多个try语句块。

    2. 寻找处理代码的过程:当异常被抛出时,程序首先搜索抛出该异常的函数,如果在当前函数没找到匹配的catch子句,就终止该函数,并在调用该函数的函数中继续寻找。

    3. 标准库函数terminate:负责终止程序的执行过程,即程序最终都没找到匹配的catch子句,就执行该函数让程序非正常退出。

    4. 没有定义try语句块:此时发生异常,系统会调用terminate函数并终止当前程序的执行。

    ————————————————2017-11-7更新补充————————————————

    补充1:当抛出一个异常后,程序(暂停当前函数的执行过程)立即开始寻找与异常匹配的catch子句

    补充2:栈展开过程,沿着嵌套函数的调用链不断查找,直到找到了与异常匹配的catch子句为止(或者也可能一直没找到匹配的catch,则退出主函数后查找过程终止)

      当throw出现在一个try语句块内时,检查与该try块关联的catch子句:

      1)找到了匹配的catch,就使用该catch处理异常

         2)未找到匹配的catch,

        ①该try语句嵌套在其他try块中,则继续检查与外层try匹配的catch子句

          1° 还是找不到匹配的catch,则退出当前的函数,在调用当前函数的外层函数中继续寻找

    补充3:若找到匹配的catch并执行完该catch,程序跳转到与try块关联的最后一个catch子句之后的那条语句继续执行,这表明了可能会跳过许多函数、语句块

    ——————————————————补充完毕———————————————————

    五、异常类

    1. 作用:报告标准库函数遇到的问题,异常类也可以用在用户编写的程序中。

    2. 定义异常类的4个头文件:

    头文件名称 说明
    exception 定义了最通用的异常类exception,它只报告异常的发生,不提供任何额外信息
    stdexcept 定义了几种常用的异常类:exception、runtime_error、range_error等
    new 定义了bad_alloc异常类型
    type_info 定义了bad_cast异常类型

    3. 头文件stdexcept中定义的异常类

    异常类 错误类型
    exception 最常见的问题
    runtime_error 只有在运行时才能检测出的问题
    range_error 运行时错误:生成的结果超出了有意义的值域范围
    overflow_error 运行时错误:计算上溢
    underflow_error 运行时错误:计算下溢
    logic_error 程序逻辑错误
    domain_error 逻辑错误:参数对应的结果值不存在
    invalid_error 逻辑错误:无效参数
    length_error 逻辑错误:试图创建一个超出该类型最大长度的对象
    out_of_range 逻辑错误:使用一个超出有效范围的值

    4. 异常类定义的几种运算:创建或拷贝异常类型的对象、为异常类型的对象赋值

    5. 不能被提供初始值的对象:exception、bad_alloc、bad_cast对象,它们只能以默认初始化的方式来初始化

    6. 不能使用默认初始化的对象:除了上面的对象,其他对象在创建时必须提供初始值(string对象或字符串字面值),该初始值含有错误相关的信息

    7. 异常类的成员函数:只有一个名为what的成员函数,该函数返回值是一个const char *(字符串字面值),目的是提供关于异常的一些文本信息。该字符串的内容与异常对象的类型有关,如果异常类型有一个字符串初始值,则what返回该字符串。而对于无初始值的异常类型来说,what返回的内容由编译器决定。

    六、示例

    题目:编写一个程序,从标准输入读取两个整数,输出第一个数除以第二个数的结果。要求:当第二个数是0时抛出异常,使用try语句块去捕获异常,catch子句应该为用户输出一条提示信息,询问是否输入新数并重新执行try语句块的内容。

    代码:

     1 #include <iostream>
     2 #include <vector>
     3 #include <cctype>
     4 #include <iterator>
     5 #include <stdexcept>
     6 #include <string>
     7 #include <cstring>
     8 
     9 using std::cin;
    10 using std::cout;    
    11 using std::endl;
    12 using std::vector;
    13 using std::string;
    14 using std::runtime_error;
    15 
    16 int main() 
    17 {
    18     int a, b;
    19     reinput:    cin >> a >> b;        //带标签语句,作为goto的目标 
    20     try {
    21         if (!b) {
    22             throw runtime_error("除数不能为0!");
    23         }
    24         cout << a / b << endl;
    25     }
    26     //err是runtime_error类的一个实例 
    27     catch (runtime_error err) {    
    28         cout << err.what();        //what是runtime_error类中的成员函数 
    29         cout << "
    是否需要重新输入? Enter y or n:" << endl;  
    30         char ch;
    31         cin >> ch;
    32         if (ch == 'n')  
    33             cout << "bye!
    "; 
    34         else
    35             goto reinput;        //reinput是用于标识一条语句的标识符 
    36     }
    37     return 0;
    38 }
    View Code

    七、小结

    • 一句话:try是检测异常的,如果产生了异常,就throw(抛出)一个异常,然后被catch到,在catch块中进行异常的处理。

     

  • 相关阅读:
    写多了博客,就想沽名钓誉
    中医与DBA
    关于OneProxy推广
    使用分布式数据库集群做大数据分析之OneProxy
    不能使用tpcc-mysql测试OneProxy
    下三滥
    建立自己的客户关系网
    编译spock proxy
    胆子还是小了
    主流语言的异常处理对比
  • 原文地址:https://www.cnblogs.com/xzxl/p/7657649.html
Copyright © 2020-2023  润新知