C++异常处理try、catch 没有finally
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了C++异常处理try、catch 没有finally,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含5888字,纯文字阅读大概需要9分钟。
内容图文
程序的错误大致可以分为三种,分别是语法错误、逻辑错误和运行时错误: 1) 语法错误在编译和链接阶段就能发现,只有 100% 符合语法规则的代码才能生成可执行程序。语法错误是最容易发现、最容易定位、最容易排除的错误,程序员最不需要担心的就是这种错误。 2) 逻辑错误是说我们编写的代码思路有问题,不能够达到最终的目标,这种错误可以通过调试来解决。 3) 运行时错误是指程序在运行期间发生的错误,例如除数为 0、内存分配失败、数组越界、文件不存在等。C++ 异常(Exception)机制就是为解决运行时错误而引入的。 ? 运行时错误如果放任不管,系统就会执行默认的操作,终止程序运行,也就是我们常说的程序崩溃(Crash)。 C++ 提供了异常(Exception)机制,让我们能够捕获运行时错误,给程序一次“起死回生”的机会,或者至少告诉用户发生了什么再终止程序。 捕获异常 我们可以借助 C++ 异常机制来捕获上面的异常,避免程序崩溃。捕获异常的语法为: try{ ????// 可能抛出异常的语句 }catch(exceptionType variable){ ????// 处理异常的语句 } 这就好比,catch 告诉 try:你去检测一下程序有没有错误,有错误的话就告诉我,我来处理,没有就pass! #include<iostream> #include<exception> ? using namespace std; ? int main(int argc, char *argv[]) { ????string str = "https://home.cnblogs.com/u/gschain/"; ????try { ????????char ch = str[100]; ????????cout<<ch<<endl; ????} catch (exception &e) { ????????cout<<"ch out of bound"<<endl; ????} ? ????try { ????????char ch1 = str.at(100); ????????cout<<ch1<<endl; ????} catch (exception &e) { ????????cout<<"ch1 out of bound"<<endl; ????} ????return 0; } 运行结果: ? ch1 out of bound ? 可以看出,第一个 try 没有捕获到异常,输出了一个没有意义的字符(垃圾值)。因为[ ]不会检查下标越界,不会抛出异常,所以即使有错误,try 也检测不到。 换句话说,发生异常时必须将异常明确地抛出,try 才能检测到;如果不抛出来,即使有异常 try 也检测不到。所谓抛出异常,就是明确地告诉程序发生了什么错误。 第二个 try 检测到了异常,并交给 catch 处理,执行 catch 中的语句。需要说明的是,异常一旦抛出,会立刻被 try 检测到,并且不会再执行异常点(异常发生位置)后面的语句。本例中抛出异常的位置是第 17 行的 at() 函数,它后面的 cout 语句就不会再被执行,所以看不到它的输出。 说得直接一点,检测到异常后程序的执行流会发生跳转,从异常点跳转到 catch 所在的位置,位于异常点之后的、并且在当前 try 块内的语句就都不会再执行了;即使 catch 语句成功地处理了错误,程序的执行流也不会再回退到异常点,所以这些语句永远都没有执行的机会了。本例中,第 18 行代码就是被跳过的代码。 执行完 catch 块所包含的代码后,程序会继续执行 catch 块后面的代码,就恢复了正常的执行流。 ? 抛出(Throw)--> 检测(Try) --> 捕获(Catch) try{ ????throw "Unknown Exception";??//抛出异常 ????cout<<"This statement will not be executed."<<endl; }catch(const char* &e){ ????cout<<e<<endl; } ? 多级 catch 当异常发生时,程序会按照从上到下的顺序,将异常类型和 catch 所能接收的类型逐个匹配。一旦找到类型匹配的 catch 就停止检索,并将异常交给当前的 catch 处理(其他的 catch 不会被执行)。如果最终也没有找到匹配的 catch,就只能交给系统处理,终止程序的运行。 #include<iostream> #include<exception> using namespace std; class Base{ }; class Derived: public Base{ }; ? int main(int argc, char *argv[]) { ????try{ ????????throw Derived();??//抛出自己的异常类型,实际上是创建一个Derived类型的匿名对象 ????????cout<<"This statement will not be executed."<<endl; ????}catch(int){ ????????cout<<"Exception type: int"<<endl; ????}catch(char *){ ????????cout<<"Exception type: cahr *"<<endl; ????}catch(Base){??//匹配成功(向上转型) ????????cout<<"Exception type: Base"<<endl; ????}catch(Derived){ ????????cout<<"Exception type: Derived"<<endl; ????} ? ????return 0; } 输出结果: Exception type: Base ? catch 在匹配过程中的类型转换 C/C++ 中存在多种多样的类型转换,以普通函数(非模板函数)为例,发生函数调用时,如果实参和形参的类型不是严格匹配,那么会将实参的类型进行适当的转换,以适应形参的类型,这些转换包括: 算数转换:例如 int 转换为 float,char 转换为 int,double 转换为 int 等。 向上转型:也就是派生类向基类的转换,请查看《C++向上转型(将派生类赋值给基类)》了解详情。 const 转换:也即将非 const 类型转换为 const 类型,例如将 char * 转换为 const char *。 数组或函数指针转换:如果函数形参不是引用类型,那么数组名会转换为数组指针,函数名也会转换为函数指针。 用户自定的类型转换。 ? #include <iostream> using namespace std; int main(){ ????int nums[] = {1, 2, 3}; ????try{ ????????throw nums; ????????cout<<"This statement will not be executed."<<endl; ????}catch(const int *){ ????????cout<<"Exception type: const int *"<<endl; ????} ? ????return 0; } 运行结果: Exception type: const int * nums 本来的类型是int [3],但是 catch 中没有严格匹配的类型,所以先转换为int *,再转换为const int *。 ? throw用作异常规范 throw 关键字除了可以用在函数体中抛出异常,还可以用在函数头和函数体之间,指明当前函数能够抛出的异常类型,这称为异常规范(Exception specification),有些教程也称为异常指示符或异常列表。请看下面的例子: double func (char param) throw (int); 这条语句声明了一个名为 func 的函数,它的返回值类型为 double,有一个 char类型的参数,并且只能抛出int类型的异常。如果抛出其他类型的异常,try将无法捕获,只能终止程序。 ? 如果函数会抛出多种类型的异常,那么可以用逗号隔开: double func (char param) throw (int, char, exception); ? 如果函数不会抛出任何异常,那么( )中什么也不写: double func (char param) throw (); ? 如此,func() 函数就不能抛出任何类型的异常了,即使抛出了,try 也检测不到。 int disp() throw(int, int) { ????int i = 1; ????if (i == 1) throw 1, 3; ????return i; } ? C++语言本身或者标准库抛出的异常都是 exception 的子类,称为标准异常(Standard Exception)。你可以通过下面的语句来捕获所有的标准异常: try{ ????//可能抛出异常的语句 }catch(exception &e){ ????//处理异常的语句 } ? 为何C++不提供“finally”结构 因为C++提供了另一种 机制,完全可以取代finally,而且这种机制几乎总要比finally工作得更好:就是——“分配资源即初始化”。 在C++中通常使用RAII,即Resource Aquisition Is Initialization. 就是将资源封装成一个类,将资源的初始化封装在构造函数里,释放封装在析构函数里。要在局部使用资源的时候,就实例化一个local object。 在抛出异常的时候,由于local object脱离了作用域,自动调用析构函数,会保证资源被释放内容总结
以上是互联网集市为您收集整理的C++异常处理try、catch 没有finally全部内容,希望文章能够帮你解决C++异常处理try、catch 没有finally所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。