现在的位置: 首页 > 综合 > 正文

C++ How To Program整理(12)

2013年02月27日 ⁄ 综合 ⁄ 共 6116字 ⁄ 字号 评论关闭

@异常处理使得程序员能够将错误处理代码从程序执行的“主流程”中分离出来,提高程序的清晰度。
@在c++中,整数除法中如果除以0,程序将过早终止,在浮点数除法中,除数为0在一些版本的C++中是被允许的,它的结果是正或负的无穷大,输出为INF或-INF。
@runtime_error类,是标准库exception类的派生类,是C++描述运行时错误所创建的标准基类。
@exception是描述所有异常而创建的标准基类。
@一个从runtime_error派生而来的典型异常类只需要定义一个构造函数,这个构造函数将带有错误信息的字符串传递给基类runtime_error的构造函数
@几乎所有的异常类都从拥有一个virtual函数what的exception类派生而来,该函数返回异常项的错误信息。
  例子: 一个处理除数为0的异常的类
         #include<stdexcept>
         using namespace std;
        
         class DivideByZeroException:public runtime_error
         {
           public:
                DivideByZeroException():runtime_error("divid by zero")
                {}
         };
        
         验证代码:
         
          #include "DivideByZeroException.h"
          #include <iostream>
          using namespace std;
         
          double quotient(int numerator,int demoninator)
          {
            if(demoninator==0)
               throw DivideByZeroException();
              
               return static_cast<double> (numerator)/demoninator;        
          }
         
          int main()
          {
             int number1;
             int number2;
             double result;
            
             cout<<"Enter two integers(end of file to end)";
            
             while(cin>>number1>>number2)
             {
                try
                {
                  result= quotient(number1,number2);
                  cout<<"the quotient is:"<<result<<endl;
                }
               catch(DivideByZeroException &divideByZeroException)
               {
                 cout<<"Exception occurred:"<<divideByZeroException.what();       

               }           
            
             }
 
          }
         
@c++提供try语句块使之能够进行异常处理,一个try语句块由关键字try和后面跟着的一对花括号构成,花括号中定义了可能发生错误的语句块。
@异常是在catch中捕获和处理的,在每个try后应该立即跟着至少一个catch,catch后面跟着的圆括号包含异常参数,说明该catch所能处理的异常类型。
@当一个try块中异常发生时,那么将要执行的就是能够匹配这个异常的catch处理器。
@注意,一个catch处理器只有一个参数,多个参数是错误。
@不能在一个try语句后有两个catch处理器捕获相同的异常。
@如果异常发生在try语句块中,并且没有匹配的catch处理器,或者异常语句不再try语句块中,则拥有该语句的函数将立即终止,并且程序将尝试
定位调用函数中封装的try语句块,这个过程称为堆栈展开。
@异常处理是设计用来处理同步错误的,不处理异步事件,只写时间发生在语句正在执行的时候,常见的例子是:数组下标越界,运算溢出,除数为零,无效的函数参数和内存分配失败。         

@执行在catch处理器外的空throw语句将导致函数terminate被调用,程序放弃异常处理,并立即结束。
@catch处理器可以通过"throw;"重新抛出异常。
 重新抛出异常的例子:
            #include<iostream>
            #include<exception>
            using namespace std;
           
            void throwException()
            {
              try
              {
                 cout<<"before exception";
                 throw exception();
              }
              catch(exception &)
              {
                cout<<"exception happened";
                throw;
              }   
            }
           
            int main()
            {
              try
              {
                cout<<"before excute function";
                throwException();
              }
              catch(exception &)
                {
                  cout<<"exception handle again.";
                }      
            }
           
@异常规格,首先最好不要使用异常规格,除非重写一个已有异常规格的基类函数。
@异常规格声明如下:
          int someFunction(double value)
                  throw(ExceptionA, ExceptionB, ExceptionC)
                  {
                  }
  由上面可以看出,异常规格由紧接着函数参数列表的关键字throw开始,throw之后包含了能够抛出的异常类型
  如果函数抛出了这些类型之外的异常,那么异常处理机制将会调用unexpected来处理,throw()不含任何参数,表示不抛出异常,如果抛出,将调用unexception()
@堆栈展开,当异常被抛出但是没有在一个特定区域被捕获,该函数的调用堆栈将被展开,别试图在展开的外部try。。catch中捕获该异常。
  这要看下面的代码来理解更容易
                 #include<iostream>
                 #include<stdexcept>
                
                 using namespace std;
                
                 void function3()throw(runtime_error)
                 {
                   cout<<"in function3"<<endl;
                   throw runtime_error("runtime error in function3“);
                 }
               
                void function2()throw(runtime_error)
                 {
                   cout<<" function3 is called in func2"<<endl;
                   function3();
                 }    
                
                  void function1()throw(runtime_error)
                 {
                    cout<<" function2 is called in func2"<<endl;
                    function2();
                 }
                 
                 int main()
                 {
                   try
                   {
                    cout<<"function is called inside main"<<endl;
                    function1();
                   }
                   catch(runtime_error &error)
                   {
                     cout<<"Exception occurred:"<<error.what()<<endl;
                     cout<<"Exception handled in main"<<endl;                 
                   }
           }
 首先function1()被执行,调用function2,function2被执行调用function3,function3抛出异常,但是没有异常处理,所以堆栈展开,
 返回到function2,function2中也没有异常处理,所以继续展开到function1,function1中也没有,返回到main,main函数中有,所以catch被执行。
 @处理new失败
    1,C++标准指出,对于到new操作错误时,应当抛出bad_alloc异常(在头文件<new>中),下面是这种例子
              #include<iostream>
              #include<new>
             
              using namespace std;
             
              int main()
              {
                 double *ptr[50];
                
                 try
                 {
                    fot(int i=0;i<50;i++)
                    {
                      ptr[i]=new double[5000000];
                      cout<<"ptr["<<i<<"] ok";                
                    }
                 }
                 catch(bad_alloc &memoryException)
                 {
                  cout<<"Exception occurred"<<memoryException.what();             

                 }
              }          
  注意:(首先不推荐)在旧版本的C++中,new失败时将返回0,c++标准规定符合标准的编译器可以继续使用在失败时返回0的new版本,
  所以头文件<new>定义了nothrow对象(nothrow_t类型)用法如下
      double ×ptr=new(nothrow)double[78967895];
      上述语句使用了没有抛出bad_alloc的new版本分配内存。
    2,处理new失败的另一种方法是使用函数set_new_handler(在头文件<new>中)
     该函数的参数是一个没有参数没有返回值的函数指针。
     当new失败时,该函数被调用。这种犯法需要提前注册,如果没有注册new失败时候将会抛出bad_alloc异常。
    
     c++明确规定new处理器将要完成以下工作中的一个
        1,通过释放其他动态内存来增加可用内存,并返回运算符new来尝试再次分配内存。
        2,抛出bad_alloc异常
        3,调用函数abort或exit(在cstdlib中)
    下面是例子
      #include<iostream>
      #include<new>
      #include<cstdlib>
     
      void newHandler()
      {
        cout<<"called"<<endl;
        abort();
      }   
     
     
      int main()
      {
        double *ptr[50];
       
        set_new_handler(newHandler);
       
         fot(int i=0;i<50;i++)
            {
              ptr[i]=new double[5000000];
              cout<<"ptr["<<i<<"] ok";                
             }
      }
                         

抱歉!评论已关闭.