武汉c培训
达内武汉中心

15271940953

热门课程

武汉C++培训:异常处理入门(try和catch)

  • 时间:2016-05-16
  • 发布:严长生
  • 来源:微学苑

编译器能够保证代码的语法是正确的,但是对逻辑错误和运行时错误却无能为力,例如除数为 0、内存分配失败、数组越界等。这些错误如果放任不管,系统就会执行默认的操作,终止程序运行,也就是我们常说的程序崩溃(Crash)。

优秀的程序员能够从故障中恢复,或者提示用户发生了什么;不负责任的程序员放任不管,让程序崩溃。C++提供了异常机制,让我们能够捕获逻辑错误和运行时错误,并作出进一步的处理。

一个程序崩溃的例子:
  1. #include<iostream>
  2. usingnamespacestd;
  3. intmain(){
  4. stringstr="c plus plus";
  5. charch1=str[100];//下标越界,ch1为垃圾值
  6. cout<<ch1<<endl;
  7. charch2=str.at(100);//下标越界,抛出异常
  8. cout<<ch2<<endl;
  9. return0;
  10. }
运行代码,在控制台输出 ch1 的值后程序崩溃。下面我们来分析一下。

at() 是 string 类的一个成员函数,它会根据下标来返回字符串的一个字符。与“[ ]”不同,at() 会检查下标是否越界,如果越界就抛出一个异常(错误);而“[ ]”不做检查,不管下标是多少都会照常访问。

上面的代码中,下标 100 显然超出了字符串 str 的长度。由于第 6 行代码不会检查下标越界,虽然有逻辑错误,但是程序能够正常运行。而第 8 行代码则不同,at() 函数检测到下标越界会抛出一个异常(也就是报错),这个异常本应由程序员处理,但是我们在代码中并没有处理,所以系统只能执行默认的操作,终止程序执行。

捕获异常

在C++中,我们可以捕获上面的异常,避免程序崩溃。捕获异常的语法为:

try{
    // 可能抛出异常的语句
}catch(异常类型){
    // 处理异常的语句
}

try 和 catch 都是C++中的关键字,后跟语句块,不能省略“{ }”。try 中包含可能会抛出异常的语句,一旦有异常抛出就会被捕获。从“try”的意思可以看出,它只是“尝试”捕获异常,如果没有异常抛出,那就什么也不捕获。catch 用来处理 try 捕获到的异常;如果 try 没有捕获到异常,就不会执行 catch 中的语句。

修改上面的代码,加入捕获异常的语句:
  1. #include<iostream>
  2. usingnamespacestd;
  3. intmain(){
  4. stringstr="c plus plus";
  5. try{
  6. charch1=str[100];
  7. cout<<ch1<<endl;
  8. }catch(exceptione){
  9. cout<<"[1]out of bound!"<<endl;
  10. }
  11. try{
  12. charch2=str.at(100);
  13. cout<<ch2<<endl;
  14. }catch(exceptione){
  15. cout<<"[2]out of bound!"<<endl;
  16. }
  17. return0;
  18. }
运行结果:
(
[2]out of bound!

可以看出,第一个 try 没有捕获到异常,输出了一个垃圾值。因为“[ ]”不会检查下标越界,不会抛出异常,所以即使有逻辑错误,try 什么也捕获不到。

第二个 try 捕获到了异常,并跳转到 catch,执行 catch 中的语句。需要说明的是,异常一旦抛出,会立即被捕获,而且不会再执行异常点后面的语句。本例中抛出异常的位置是第 15 行的 at() 函数,它后面的 cout 语句不会再被执行,也就看不到输出。

异常类型

所谓抛出异常,实际上是创建一份数据,这份数据包含了错误信息,程序员可以根据这些信息来判断到底出了什么问题,接下来该怎么处理。

异常既然是一份数据,那么就应该有数据类型。C++规定,异常类型可以是基本类型,也可以是标准库中类的类型,还可以是自定义类的类型。C++语言本身以及标准库中的函数抛出的异常,都是 exception 类或其子类的类型。也就是说,抛出异常时,会创建一个 exception 类或其子类的对象。

异常被捕获后,会和 catch 所能处理的类型对比,如果正好和 catch 类型匹配,或者是它的子类,那么就交给当前 catch 块处理。catch 后面的括号中给出的类型就是它所能处理的异常类型。上面例子中,catch 所能处理的异常类型是 exception,at() 函数抛出的类型是 out_of_range,out_of_range 是 exception 的子类,所以就交给这个 catch 块处理。

catch 后面的exception e可以分为两部分:exception 为异常类型,e 为 exception 类的对象。异常抛出时,系统会创建 out_of_range 对象,然后将该对象作为“实参”,像函数一样传递给“形参”e,这样,在 catch 块中就可以使用 e 了。

其实,一个 try 后面可以跟多个 catch,形式为:

try
{
    //可能抛出异常的语句
}
catch (exception_type_1)
{
    //处理异常的语句
}
catch (exception_type_2)
{
    //处理异常的语句
}
// ……
catch (exception_type_n)
{
    //处理异常的语句
}

异常被捕获时,先和 exception_type_1 作比较,如果异常类型是 exception_type_1 或其子类,那么执行当前 catch 中的代码;如果不是,再和 exception_type_2 作比较……依此类推,直到 exception_type_n。如果最终也没有找到匹配的类型,就只能交给系统处理,终止程序。

多个 catch 块的例子:
  1. #include<iostream>
  2. #include<exception>
  3. #include<stdexcept>
  4. usingnamespacestd;
  5. //自定义错误类型
  6. classmyType:publicout_of_range{
  7. public:
  8. myType(conststring&what_arg):out_of_range(what_arg){}
  9. };
  10. intmain(){
  11. stringstr="c plus plus";
  12. try{
  13. charch1=str.at(100);
  14. cout<<ch1<<endl;
  15. }catch(myType){
  16. cout<<"Error: myType!"<<endl;
  17. }catch(out_of_range){
  18. cout<<"Error: out_of_range!"<<endl;
  19. }catch(exception){
  20. cout<<"Error: exception!"<<endl;
  21. }
  22. return0;
  23. }
运行结果:
Error: out_of_range!

try 捕获到异常后和第一个 catch 对比,由于此时异常类型为 out_of_range,myType 是 out_of_range 的子类,所以匹配失败;继续向下匹配,发现第二个 catch 合适,匹配结束;第三个 catch 不会被执行。

需要注意的是:catch 后面的括号中仅仅给出了异常类型,而没有所谓的“形参”,这是合法的。如果在 catch 中不需要使用错误信息,就可以省略“形参”。
上一篇:武汉C++培训:string字符串的增删改查
下一篇:武汉C++培训:throw:抛出自己的异常
选择城市和中心
贵州省

广西省

海南省