20170226C++项目班05_C/C++错误异常处理

来源:互联网 发布:淘宝加盟诈骗案进展 编辑:程序博客网 时间:2024/05/29 13:39

Calc作业(修改bug):

1:调试能力是工作必备能力之一。

2:调试应该先找到错误的源头,然后根据编程时候的逻辑线单步执行,然后在没有按照预期执行的代码段找原因。

    注意:不能导出下断点,最后自己的逻辑就错乱了,很难找到bug所在

C语言错误处理方式:

1:我们之前用的最多的是通过返回值来判断是否执行成功,返回值往往是bool类型。但是不能判断出出错在哪个地方。

2:在文件操作的时候,在很多过程的时候都是可能出错的。

    openFile:文件不存在

    writeFile:无法写入

    closeFile:无法关闭

  我们可以写一个enum{ERROR_OPEN……},返回回来就可以表明错误类型,称为errorcode。

3:在方法内的错误处理,现在一般用dowhile。

4:使用jmp来实现:

#include <stdio.h>#include <setjmp.h>jmp_buf env;double Div(double d1, double d2){if (d2 == 0.0)longjmp(env, 1);//会直接跳到setjmp的地方,然后将跳到ret=1的里面去执行。return d1 / d2;}int main(){int ret;ret = setjmp(env);//当执行到longjmp的时候就会跳到这里来。重新个给ret赋值。if (ret == 0)//setjmp的时候,env默认就是为0,所以一般把正常要执行的代码放到=0的里面。{Div(5.0, 0.0);}else if (ret == 1)//在这里面也可以使用longjmp,跳出去。{printf("Div_Error");}return 0;}

5:longjmp并不是一个返回,他是一个跳转。相当于goto。他什么都不管,直接就跳转了。这种处理方式和C++里面的try chtch是一模一样的。

C++异常处理:

1:两种错误:

    1:编译错误/语法错误:人为的,编译器会提示错误原因

    2:运行时错误/语义错误:有很多种情况:

        打开文件失败、被除数为0、内存不够……

2:异常体系:

    runtime_error:

    logic_error:

使用异常体系:第一步:throw,第二步:try,第三步:catch。

#include <iostream>#include <cfloat>enum EMyException{E_DIVERROR,E_FOOERROR};double Div(double d1, double d2){if (d2<DBL_EPSILON && d2>-DBL_EPSILON)throw E_DIVERROR;}void Foo(){throw E_FOOERROR;}int main(){try{Div(5.0, 0.0);Foo();}catch (EMyException e){if (e == 0)//这里会有隐式转换,如果出错会打印值printf("DivError");else if (e == E_FOOERROR)printf("FooError");}return 0;}

注意:这种try catch比C语言的逻辑更加简单,当遇到throw的时候,抛出异常,他会向前寻找有try和catch的地方,并在里面做相应的处理。

3:C++的异常可以抛出各种各样的类型:字符串指针、int、类成员类型……当catch里面没有对应的时候他会适当的转换,不能转换的时候,他还是会抛给编译器来处理,一般就会直接报错,程序终止。下面抛出自己写的异常类:

#include <iostream>#include <string>#include <cfloat>enum EMyException{E_DIVERROR,E_FOOERROR};class MyExcept{public:MyExcept(const std::string &str);void What() const;private:std::string str_;};MyExcept::MyExcept(const std::string &str):str_(str){if (str_.empty())throw "str_不能为空";//throw可以在任何一个地方出现(析构函数除外)。}void MyExcept::What() const{std::cout << str_ << std::endl;}double Div(double d1, double d2){if (d2<DBL_EPSILON && d2>-DBL_EPSILON)throw E_DIVERROR;return d1 / d2;}void Foo(){throw E_FOOERROR;}int main(){std::string ErrorCode = "Object_Error";try{Div(5.0, 0.5);throw MyExcept(ErrorCode);Foo();}catch (EMyException e){if (e == 0)//这里会有隐式转换,如果出错会打印值printf("DivError");else if (e == E_FOOERROR)printf("FooError");}catch (MyExcept e){e.What();}catch (...){printf("捕获所有异常");}return 0;}

4:异常可以在任何地方出现,包括构造函数,但是不可以在析构函数里面,而且,C++异常是安全的,他是栈安全的,当throw的时候,他会逆向按原来的顺序反回去清理栈空间,但是不会清理堆空间。throw的时候,他会按照栈来返回,返回到catch到这个的地方,如果没有任何一个地方catch,就会交给编译器,就出现我们常见的异常。我们在销毁栈的时候就是在销毁局部变量,如果是类对象的话,他还会调用析构函数。

#include <iostream>#include <string>#include <cfloat>class Text{public:Text(int id) :id_(id) { std::cout << "Text"<< id_ << std::endl; }~Text(){ std::cout << "~Text" << id_ << std::endl; }Text(const Text& text) :id_(text.id_){std::cout << "Text(Text(Text&text))" << id_ << std::endl; }private:int id_;};class MyExcept{public:MyExcept(const std::string &str);void What() const;private:std::string str_;};Text& Foo4(){Text *text = new Text(4);return *text;}Text Foo3(){Text text(3);Text t1 = Foo4();throw MyExcept("Foo3");}void Foo2(Text text){Foo3();}void Foo1(Text &text){Foo2(text);}MyExcept::MyExcept(const std::string &str) :str_(str){if (str_.empty())throw "str_不能为空";//throw可以在任何一个地方出现(析构函数除外)。}void MyExcept::What() const{std::cout << str_ << std::endl;}int main(){try{Foo1(Text(1));}catch (MyExcept e){e.What();}return 0;}

new出来的在堆上,没有释放。

    注意:要保证对上的数据也安全,只能在throw的前面把堆上面的空间清理掉。

5:异常类也是可以继承的,可以分为不同种的异常类。

    1:在catch的时候派生类必须写在基类之前,否则他会认为这种异常就是基类的。后面的catch派生类就没有作用。

    2:非迫不得已,永远不要抛出指针。指针可能是指向栈的,而整个异常体系是清理栈的,可能导致问题。热和一个指针都可以被void*捕获。还可以那引用来接收,这样就不会产生copy。

6:C++已经包含的异常:

    1:所有异常的基类:std::exception://What();,下面的属于exception的直接的派生类。

        std::runtime_error:运行时出错

            std::overflow_error:

            std::range_error:

            std::underflow_error:

        std::logic_error:逻辑错误:

            std::invalid_error:

            std::length_error:

            std::out_of_range:

            std::domain_error:

        std::bad_alloc:分配的时候出现错误。

        std::bad_cast:类型转换错误。

7:catch操作注意事项

    1:因该先捕获自己写的异常,然后捕获其他异常,最后用...捕获其他的所有异常。

    2:可能在其他人写的代码里面看见一个函数后面更了一个except(),代表宰割函数会抛出异常,仅给程序员看,不建议写。

    3:不要再析构函数里面抛出异常,可能出现一个异常未处理完有出现另一个异常,会直接导致程序退出。



1 0