大佬教程收集整理的这篇文章主要介绍了《C++ Primer》笔记之异常处理,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
1.@R_450_5179@ 异常处理的使用 首先说明,千万别对异常处理钻牛角尖,那样会死人的(当然是烦死的)! 在C++编程处理中,我秉承这样一个思想,就是:能不用异常处理的就不用。因为造成的混乱实在是太——多了。如果能用其他方法捕捉到错误并处理的话,誓死不用异常处理!呵呵,或许有点偏激,但我认为,这不失为一个避免不必要的错误的一个好办法。当什么分配内存失败,打开文件失败之类的通常错误,我们只需用assert,abort之类的函数就解决问题了。也就是说,假如有足够的信息去处理一个错误,那么这个错误就不是异常。 @R_450_5179@ 当然了,异常处理的存在也有它本身的意义和作用。不是你说不用就不用的,有些地方还非得用不可! @R_450_5179@ 比如说,在当前上下文环境中,无法捕捉或确定的错误类型,我们就得用一个异常抛出到更大的上下文环境当中去。还有,异常处理的使用呢,可以使出错处理程序与“通常”代码分离开来,使代码更简洁更灵活。另外就是程序必不可少的健壮性了,异常处理往往在其中扮演着重要的角色。 @R_450_5179@ OK,下面阐述一下。 2.@R_450_5179@ 抛出异常 关——键字(周星驰的语气):throw 例——句:throw ExceptionClass(“oh,shit! it’s a exception!L “); 例句中,ExceptionClass是一个类,它的构造函数以一个字符串做为参数,用来说明异常。也就是说,在throw的时候,C++的编译器先构造一个ExceptionClass的对象,让它作为throw的返回值,抛——出去。同时,程序返回,调用析构。看下面这个程序: #include <iostream.h> class ExceptionClass{ @R_450_5179@ char* name; public: @R_450_5179@ ExceptionClass(char* name="default name")@R_450_5179@ { @R_450_5179@@R_450_5179@ cout<<"Construct "<<name<<endl; @R_450_5179@@R_450_5179@ this->name=name; @R_450_5179@ } @R_450_5179@ ~ExceptionClass()@R_450_5179@ { @R_450_5179@@R_450_5179@ cout<<"Destruct "<<name<<endl; @R_450_5179@ } @R_450_5179@ throw ExceptionClass("o,my god"); }@R_450_5179@ }; void main(){ @R_450_5179@ ExceptionClass e("haha"); @R_450_5179@@R_450_5179@ e.myThrow(); @R_450_5179@ }@R_450_5179@ catch(...) { @R_450_5179@ } } 大家看看结果就知道了,throw后,调用当前类的析构,整个结束了这个类的历史使命。唉~~ 3.@R_450_5179@ 异常规格说明 如果我们调用别人的函数,里面有异常抛出,我用去查看它的源代码去看看都有什么异常抛出吗?可以,但是太——烦躁。比较好的解决办法,是编写带有异常抛出的函数时,采用异常规格说明,使我们看到函数声明就知道有哪些异常出现。 异常规格说明大体上为以下格式: void ExceptionFunction(argument…) throw(ExceptionClass1,ExceptionClass2,….) 对了,所有异常类都在函数末尾的throw()的括号中得以说明了,这样,对于函数调用者来说,是一清二楚了! 注意下面一种形式: void ExceptionFunction(argument…) throw() 表明没有任何异常抛出。 而正常的void ExceptionFunction(argument…)则表示:可能抛出任何一种异常,当然就,也可能没有异常,意义是最广泛的哦。 4.@R_450_5179@ 构造和析构中的异常抛出 55555,到了应该注意的地方了。 @R_450_5179@ 先看个程序,假如我在构造函数的地方抛出异常,这个类的析构会被调用吗?可如果不调用,那类里的东西岂不是不能被释放了?? @R_450_5179@ 程序: #include <iostream.h> #include <stdlib.h> class ExceptionClass1{ @R_450_5179@ char* s; public: @R_450_5179@ ExceptionClass1(){ @R_450_5179@@R_450_5179@ cout<<"ExceptionClass1()"<<endl; @R_450_5179@@R_450_5179@ s=new char[4]; @R_450_5179@@R_450_5179@ cout<<"throw a exception"<<endl; @R_450_5179@@R_450_5179@ throw 18; @R_450_5179@ } @R_450_5179@ ~ExceptionClass1(){ @R_450_5179@@R_450_5179@ cout<<"~ExceptionClass1()"<<endl; @R_450_5179@@R_450_5179@ delete[] s; @R_450_5179@ } }; void main(){ @R_450_5179@@R_450_5179@ ExceptionClass1 e; @R_450_5179@ }catch(...) } 结果为: ExceptionClass1() throw a exception 没了,没了,到此为止了!可是,可是,在这两句输出之间,我们已经给S分配了内存,哪里去了?内存释放了吗?没有,没有,因为它是在析构函数中释放的,哇!问题大了去了。怎么办?怎么办? 为了避免这种情况,应避免对象通过本身的构造函数涉及到异常抛出。即:既不在构造函数中出现异常抛出,也不应在构造函数调用的一切东西中出现异常抛出。否则,只有完蛋。 那么,在析构函数中的情况呢?我们已经知道,异常抛出之后,就要调用本身的析构函数,如果这析构函数中还有异常抛出的话,则已存在的异常尚未被捕获,会导致异常捕捉不到哩。 5.@R_450_5179@ 异常捕获 上边的程序不知道大家看懂了没,异常捕获已经在上面出现了也。 Try后面的花括号中,就是有可能涉及到异常的各种声明啊调用啊之类的,如果有异常抛出,就会被异常处理器截获捕捉到,转给catch处理。先把异常的类和catch后面小括号中的类进行比较,如果一致,就转到后面的花括号中进行处理。 例如抛出异常是这么写的: void f(){throw ExceptionClass(“ya,J”);} 假设类ExceptionClass有个成员函数function()在有异常时进行处理或相应的消息显示(只是做个例子哦,别挑我的刺儿)。 那么,我可以这么捕捉: try{f()}catch(ExceptionClass E){e.function()}; 当然,象在上面程序中出现的一样,我可以在catch后用三个点来代表所有异常。如try{f()}catch(…){}。这样就截断了所有出现的异常。有助于把所有没出现处理的异常屏蔽掉(我是这么认为的J)。 异常捕获之后,我可以再次抛出,就用一个不带任何参数的throw语句就可以了,例如:try(f())catch(…){throw} |
以上是大佬教程为你收集整理的《C++ Primer》笔记之异常处理全部内容,希望文章能够帮你解决《C++ Primer》笔记之异常处理所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。