C++异常处理机制

来源:互联网 发布:krpano全景漫游软件 编辑:程序博客网 时间:2024/05/16 14:57

一、前言

    以前在学习C语言,其实就接触过异常处理机制,但是当时抱着一种反正现在用不到,以后碰到再学习的心态,就没有深究其具体机制,这里以个人体会提醒广大博友同学,这样的心态要不得,如果你专心想学习一门语言或一个技术,每当你遇到一个该语言或该技术的新的特性,你就应该打破砂锅问到底,如果每当你也是抱着我当初那样的心态,那你永远不会学到真正的技术。现在在C++语言中又遇到了异常处理机制,索性就弄清楚它。


二、异常发生后行为

    首先,需要理解什么是程序异常?所谓程序异常,是指存在于程序运行时的反常行为,也就是说程序执行到某处(异常处),没有按照你的编写逻辑运行,而是意外终止或执行了一些其他的代码。

    其次,需要知道异常发生后,程序的行为是什么?最常见的我们在用到数组或vector时,常常会遇到访问越界(out of range)的异常,这时程序往往是终止运行的,并弹出一个错误提示信息,注意,这里的程序终止(即异常发生后程序的行为),是在异常发生的地方终止了整个程序(或一个函数调用),在发生异常地方后面的代码是不会再执行的。


三、C++异常处理机制

    C++异常处理机制包括:异常检测异常处理两个部分,顾名思义,异常检测就是检测(也说为抛出)一个异常,异常处理就是处理抛出的异常,这二者分别对应了一个异常检测表达式代码和异常处理代码块。

(1)异常检测

    异常检测部分是由throw关键字标识的一个表达式,具有以下形式:

    throw error_type("初始化值");

这里,throw就是一个关键字,表示这里抛出(检测)一个异常,error_type是一个异常类型(就是一种C++标准类型,与string等是一样的地位),C++标准中定义了多种异常类型,最常见的有runtime_error、out_of_range等,既然error_type所示的是一种类型,那error_type("初始化值")这种形式的写法就是调用该异常类型的构造函数,构造一个该异常类型的对象,其中"初始化值"一般是string对象和C风格字符串,比如抛出一个out_of _range异常的完整写法为:throw out_of_range("out of array range!");

(2)异常处理

    异常处理部分是一个代码块,这个代码块包含一个tyr语句块(一对花括号表示),然后紧跟着多个连续的catch语句块(多个花括号表示),具体形式如下:

try

{

//异常检测的throw表达式放在try语句块中

//同时,这里也是程序的正常逻辑代码,就是说去掉tyr、throw和花括号,这里面的代码是你整个程序的一部分

}

//紧跟多个catch语句块,try和第一个catch之间不能有其他代码,不然就出现了try和catch不匹配的错误,这里和if......else是一样的

catch(error_type m_error){}

catch(error_type m_error){}

对于异常处理部分,两个地方需要注意:1)第一个catch必须紧跟try语句块;2)每个catch需要声明一个异常类型对象,这里声明的对象只能在本catch语句块(自己的花括号范围)内使用。对于第二点,你可能在想,这里只是声明了,并没有定义(或赋予它初值),那我们怎么在catch的花括号范围内使用呢?其实这个问题链接器已经为我们考虑并自己执行了,怎么执行的呢?其实catch声明的异常类型对象是被拷贝初始化的,从哪里拷贝过来?就是throw表达式返回的异常类型对象,仔细体会一下这个流程,链接器默认把throw构造的异常类型对象传递给了该异常类型的拷贝构造函数,然后catch部分对每一个异常进行捕获,如果捕获成功,就调用相应的异常类型的拷贝构造函数。


四、异常捕获过程

    对第二部分解释的异常发生后,程序会从异常出现的地方终止并返回,这是在没有异常处理代码的情况下,如果你写了异常处理代码,即用throw抛出一个异常,并用try和catch语句块捕获并处理该异常,那程序就不会异常终止,只是会跳过一部分代码(即throw后的代码不会执行)。

    这里总结一下,添加了异常处理代码后的程序执行流程,在说明过程中,假设程序中只有一个异常处理过程,不存在嵌套的异常处理代码,具体流程如下:

    /*************************************/

    程序正常执行,执行到try部分;

    继续执行try语句块;

        执行到throw表达式时,抛出一个异常;

        程序跳转到从紧跟try语句块的第一个catch语句块第一个执行;

    依次匹配每个catch语句块声明的异常类型是否与throw表达式抛出的异常类型一致

        如果一致,执行本catch语句块内部代码;

        如果不一致,匹配写一个catch语句块;

    如果,没有匹配到的catch,则程序终止;

    如果匹配到一个catch语句块,执行其内部代码之后,程序跳转到最后一个catch语句块之后的代码继续执行,完成整个程序。

    /**************************************/


五、总结

    要理解C++异常处理机制,首先要理解异常处理的基本流程,即异常从哪里抛出(throw),抛出异常之后程序怎么执行(跳转到对应catch语句块),异常处理完成之后程序又怎么执行(再跳转到最后一个catch之后的代码);其次,对于C++面向对象的思想(有很多大牛都批评是只是伪面向对象),即一切都是类,一切都是对象,那当然异常也是一个类型,也可以声明和定义一个异常对象,并调用其相应的成员函数和访问数据成员。


六、异常处理例子

    这里举一个简单的异常处理的例子,大致内容是一个简单的文本转换程序(C++Primer第五版P391,第11章),博友可以先尝试运行下面的代码,就能知道代码的具体任务,然后重点关注异常处理代码部分的变化会造成怎么样的影响。

#include <iostream>#include <fstream>#include <sstream>#include <map>#include <string>using namespace std;//map映射建立函数,由于每个规则不一样,因此用map就行map<string, string> Buildmap(ifstream& s){map<string, string> trans_rule_map;      //转换规则映射string key;     //要转换的单词string value;   //转换的文本while(s>>key && getline(s, value)){/************如果注释掉try则会报错************/try{if(value.size() > 1)     //判断是否有转换规则{trans_rule_map[key] = value.substr(1);    //使用map下标操作,如果key不在map内,则添加}else{cout << "Befor Error throw!" << endl;//这里抛出一个runtime_error类型异常,并为该异常提供初始值,这个过程中用到了string类型的+操作符,用于连接两个string//一旦这个异常发生,则会终止该函数,不会再执行下面的代码。//上述抛出异常的代码其实就是一个函数返回的过程,即调用runtime_error类型构造函数,返回一个异常类对象,这个对象回传递给catch部分throw runtime_error("no transfrom rule for " + key + "!");     cout << "After Error throw!" << endl;}}//cout << 1 << endl;         //这里导致catch和try不连续,会报错//这里添加了异常处理代码,程序从抛出异常的位置跳转到对应的异常处理代码处(不会再执行try语句块中throw后面的代码),//异常处理代码处理完成之后,程序跳转到最后一个catch语句块之后的代码继续执行/************如果注释掉catch则会报错************/catch (runtime_error runerr){cout << runerr.what() << endl;     //输出异常提示信息,每个异常类只有一个成员函数,即what(),用来返回异常提示信息,这个提示信息就是初始化异常类型时的string或者C风格字符串}}return trans_rule_map;}//转换函数void Transfrom(ifstream& s, const map<string, string> &rulemap){string line;string word;while(getline(s, line))     //读取一行内容,遇到换行符终止,line中没有换行符{istringstream istr(line);     //创建内存IO流对象,读取string对象内容while(istr >> word){auto mapiter = rulemap.find(word);if(mapiter != rulemap.end())cout << mapiter->second << " ";elsecout << word << " ";}cout << endl;}}//主函数,转换并输出文本void main(){ifstream in1("C:/Users/ZWX/Desktop/text.txt");ifstream in2("C:/Users/ZWX/Desktop/text2.txt");auto transrulemap = Buildmap(in1);Transfrom(in2, transrulemap);}


text.txt如下:

k okay?y whyr areu youpic picturethk thanks!18r later


text2.txt如下:

where r uy dont u send me a pick thk 18r


运行结果如下:





原创粉丝点击