zoukankan      html  css  js  c++  java
  • 备忘:VC++ 中的异常处理

        当程序遇到一个异常或一个严重的错误时,通常意味着它不能继续正常运行并且需要停止执行。任何的设计都离不开对异常与错误的处理。如果设计者不主动规避程序异常,往往在程序发生异常时,会被系统终止而直接退出。这对使用者来说,是很不友好的。

        如果主动处理异常,可以显式地提示错误地发生,也可以避免程序异常终止。更好的处理是,在设计时,预估一些错误,让用户避开这些错误以让程序顺利运行。对一些无法预知的异常,也需要我们通过VC++的异常处理机制,显式地告诉错误已发生,并保证程序的继续进行。

        VC++提供了两种不同性质的异常处理:
        结构化异常SEH (Structured Exception Handling, ) 和 类型化的 C++异常。
        SEH 是VC++编译器特有的,因此如果你想要编写可移植的代码,就不应当使用SEH。他只能在 Windows系统中产生作用。如果只想编写 Windows 应用。那么,最好选择SEH来处理异常。SEH 比 类型化的C++异常 更方便,更灵活。

    结构化异常SEH

       __try,__except,__finally   是Windows系列操作系统平台上提供的SEH的处理模型。

       __try,__except:表示 try {}语句中发生异常,将转到 except () {}模块执行。如果try{}没有异常。except模块被跳过。继续执行 except {} 之后的代码。

        __try, __finally :  表示try {}语句无论有没异常发生,finally{}模块都会被执行。__try __finally 没有太多用法,不作详细说明。只要用对地方就行了。

        ___leave : 一般用在 try{} 里。表示退出 try 模块,并不执行 leave之后的语句。根当于函数中的return. 不过,这里只退出try{}.

    __try,__except 简单用法示范

    int _tmain(int argc, _TCHAR* argv[])
    {
        int v1, v2;
        v1 = 1; v2 = 0;
        double x=0;
        
        __try
        {
            // if (v2==0) ___leave; 
            // 加上___leave这一句。leave 之后的代码都不会执行 跳出 try 执行 try except 之后的代码。
            x = v1 / v2; // x = myFunc(v1, v2);
            cout << x << endl;
        }
        __except (1) // 试着改为 0 或 -1 看看效果
        {
            cout << "Error!" << endl;
        }
        system("pause");
        return 0;
    }

    __except 后的括号里,是一个表达式或一个数值。表达式返回的也应是一个数值。这个数值 为 1-3 表明 except的三种处理方试:

    • __except(-1)  异常终止,退出程序。很少用这个。除非人为想终止自己的程序。

    • __except(0) 跳出当前异常,继续由下一个异常 except 来处理。

    • __except(1) 接受异常。执行异常 {} 中的语句。以上二个值 -1, 0 都不会执行 except{ ... } 中的语句。

    这三个值,在 Windows 中,有三个常量代表:

            EXCEPTION_CONTINUE_EXECUTION (– 1)
            EXCEPTION_CONTINUE_SEARCH (0)
            EXCEPTION_EXECUTE_HANDLER (1)

    我们也可以通过一个函数来返回三个值。让 except 被触发时,作更精准的处理。而这个函数一般会调用 Windows的 两个错误代码处理的API函数:
            GetExceptionCode() : 返回错误代码;
            GetExceptionInformation() : 取得错误信息结构。

    嵌入异常处理与自定义处理函数示例:

    int ErrorFunc(unsigned int code, struct _EXCEPTION_POINTERS *ep)
    {
        puts("my Error infomathion.");
    
        if (code == EXCEPTION_ACCESS_VIOLATION) {
    
            puts("caught AV as expected.");
    
            return EXCEPTION_EXECUTE_HANDLER; // =1 执行被调用的 except 处理过程
    
        }
    
        else {
    
            puts("didn't catch AV, unexpected.");
    
            return EXCEPTION_CONTINUE_SEARCH; // =0 继续让下一个 except处理
    
        };
    }
    
    double myFunc(int a, int b) 
    {
        double r;
        
        //exit(0);
        __try
        { 
        r = a / b;
        cout << "Cacle..." << endl;
        } 
        __except (ErrorFunc(GetExceptionCode(), GetExceptionInformation()))
        {
            // 如果 ErrorFunc 返回值为 1 下面的语句才会执行
            unsigned int code = GetExceptionCode();
            cout << "ERROR!:" << code  << endl;
            //throw;
        }
        cout << "...end1..." << endl;
        return r;
    }
    
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        int v1, v2;
        v1 = 1; v2 = 0;
        double x=0;
        
        __try
        {
            x = myFunc(v1, v2); // 调用函数,嵌入式 __try __except 示范。  
            cout << x << endl;
        }
        __except (1)
        {
            cout << "Error!" << endl;
        }
        cout << "...end2..." << endl;
        system("pause");
        return 0;
    }

    SEH异常处理模型中,异常通过RaiseException()函数抛出。RaiseException()函数的作用类似于C++异常模型中的throw。可以通过这个函数,主动处理预知的异常。

    主动抛出异常示例:

    int _tmain(int argc, _TCHAR* argv[])
    {
        int v1, v2;
        v1 = 1; v2 = 0;
        double x=0;
        
        __try
        {
            // x = v1 / v2;
            RaiseException(100, 0, 0, NULL); //主动抛出错误 100 是自己定义的异常代码
            cout << x << endl;
        }
        __except (1)
        {
            UINT code = GetExceptionCode();
            if (code==100) // 判断自己抛出的异常代码
              cout << "Error! Code:"<< code << endl;
        }
        cout << "...end..." << endl;
        system("pause");
        return 0;
    }

     

    类型化的 C++异常

        C++的异常处理很简单,就是三个关键字 try, throw, catch来完成。他在很多地方有关系性作用。但这里只作简单地了解。

    try
    {
      //这里写入一些代码
      int a=10, b=0;
      int x;
      if (b==0) 
        throw 1; // 抛出异常。终止以下的代码执行 。
      if (a==1);
        throw 2; // 再抛出个异常。终止以下的代码执行 。
      
      x = a/b; // b=0. 会产生运算异常。
    }
    catch int i
    {
      if (i==1) // 由 throw 抛出的值 =1
        cout << "b=0 is error!" <<endl;
      if (i==2) // 由 throw 抛出的值 =2
        cout << "i=1 is error!" <<endl;
    }
    catch(...){} //接受所有异常
    
     

        如 果想用 try{} catch{}来捕捉一些意想不到的异常,是靠不住的。也就是说他需要在 try {} 中主动发现异常,然后通过 throw, 抛出异常,让 catch来处理。如果是你发现不了的异常,如果无法throw出来,也就无法处理。如上例中: if (b==0) throw 1; 这句不要。执行到 x=a/b; 是会产生一个系统错误。try{}catch{} 中不会主动识别这个异常。但 try , catch 的用法有很多。可以找更多的资料去了解下。我也未了解清楚。

        以下内容容易不被了解:

        catch 没有捕获到匹配的异常的时候,会调用默认的终止函数。可以调用 set_terminate()来设置终止函数,参数是一个函数指针,类型是:void (*terminate)(); 实际上是调用默认的unexpected()函数,而这个默认的unexpected() 调用了 set_terminate() 中设定的终止函数。可以用set_unexpected()来设置unexpected。

    如下:( 但这一段代码在VC下编译执行不会发生什么!)

    void myUnexpected() {
        cerr << "unexpected called
    ";
        throw 0;     // throws int (in exception-specification)  
    }
    
    void myfunction() throw (int) {
        throw 'x';   // throws char (not in exception-specification)  
    }
    int _tmain(int argc, _TCHAR* argv[])
    {
        int v1, v2;
        v1 = 1; v2 = 0;
        double x=0;
        set_unexpected(myUnexpected);
        try
        {
            myfunction();  // x = v1 / v2;
        }
        catch (int) {
            cerr << "caught int/n";
        }
        catch (...){ 
            cerr << "caught other exception (non-compliant compiler?)
    "; 
        };
    }

        VC 在Release方式下如果选择了编译器代码优化选项,则会去搜索try块中的代码, 如果没有找到throw代码, 就会认为try catch结构是多余的, 给优化掉。 这样造成在Release模式下。如果不在 try{}中主动throw抛出一个异常。在VC 的 Release编译模式下,try  catch 是被忽略掉的。

     

     

       

  • 相关阅读:
    LeetCode Missing Number (简单题)
    LeetCode Valid Anagram (简单题)
    LeetCode Single Number III (xor)
    LeetCode Best Time to Buy and Sell Stock II (简单题)
    LeetCode Move Zeroes (简单题)
    LeetCode Add Digits (规律题)
    DependencyProperty深入浅出
    SQL Server存储机制二
    WPF自定义RoutedEvent事件示例代码
    ViewModel命令ICommand对象定义
  • 原文地址:https://www.cnblogs.com/iSixth/p/4179350.html
Copyright © 2011-2022 走看看