代码改变世界

c/c++的异常统一处理

2012-11-07 23:01  钱吉  阅读(1398)  评论(0编辑  收藏  举报

今天看HTK代码,发现里面的错误处理机制很好,所以自己在这里总结一下。如何将某些类型的错误集中起来统一处理,使得程序易于维护和具有更好的可读性。

这里假设有这样一个故事,有个美女征婚,理想中的男人如果要表白成功,需要具备6个条件:玫瑰(Rose),戒指(Ring),宝马(BWM),高(Tall),富(Rich),帅(Handsome)。(好吧,我承认这个故事很低俗,但是实在想不出其它例子来比喻了,将就着看吧,-_-)。如果少了一个条件,sorry,美女要抛出异常了。但是现在求婚的人太多,美女无暇顾及,所以决定先请人把关,再根据把关人反馈的结果统一处理。好了,先看C语言如何处理:

C语言错误统一处理

 1 #include <stdio.h>
 2 #include <memory.h>
 3 #include <stdarg.h>
 4 #define COUNT 6
 5 static char *pall[]={"Ring", "Rose", "BMW", "Tall", "Rich", "Handsome"};
 6  
 7 
 8 typedef struct _Condition {
 9          char *pgift[COUNT];
10          int ngift;
11 }Condition;//存储个人条件的结构体
12 static void Select(const Condition *con);
13 static void Herror(int ntype, char *str, ...);
14 int main(int argc, char **argv)
15 {
16          Condition A,B,C;
17          memset(A.pgift, 0, COUNT);
18          memset(B.pgift, 0, COUNT);
19          memset(C.pgift, 0, COUNT);
20          A.pgift[1]=pall[1]; A.ngift=1;//A->Rose
21          B.pgift[0]=pall[0]; B.pgift[5]=pall[5]; B.ngift=2;//B->Ring,Handsome
22          C.pgift[1]=pall[1]; C.pgift[2]=pall[2]; C.pgift[4]=pall[4]; C.ngift=3;//C->Rose,BMW,Rich
23          
24          Select(&A);
25          Select(&B);
26          Select(&C);
27          return 0;
28 }
29 /*****************************************
30 *根据条件考虑每个人,并调用错误统一处理函数
31 ******************************************/
32 static void Select(const Condition *con)
33 {
34          if(con==NULL)
35                    return;
36          switch(con->ngift)
37          {
38                    case 0:
39                             break;
40                    case 1:
41                             Herror(1, "fail:only have %s", con->pgift[1]);
42                             break;
43                    case 2:
44                             Herror(2, "fail:only have %s,%s", con->pgift[0], con->pgift[5]);
45                             break;
46                    case 3:
47                             Herror(3, "fail:only have %s,%s,%s", con->pgift[1], con->pgift[2], con->pgift[4]);
48                             break;
49                    default:
50                             break;
51          }
52 }
53 /********************************************
54 * 统一处理
55 * *****************************************/
56 static void Herror(int ntype, char *str, ...)
57 {
58          va_list parg;
59          FILE *f = stdout;
60          va_start(parg, str);//获取指向可变参数的第一个参数的指针
61          printf("\n---------Result--------\n");
62          if(ntype < 3)
63                    printf("pass over:");
64          else if(ntype < 5)
65                    printf("just so so:");
66          else
67                    printf("wait and see:");
68          vfprintf(f, str, parg);//输出结果
69          printf("\n----------over---------\n");
70          va_end(parg);//关闭指针
71          fflush(f);   
72 }

结构体中的ngift表示男人征婚准备的礼物数量。32行的select函数所做的工作就是把关,考擦每个男人的条件,对于不符合美女要求的,统一把把关结果反馈给Herror函数,这里Herror做的事情就是美女根据反馈结果下结论:ngift<3的直接pass掉(这美女有点物质,哈哈),介于3与5之间的她觉得一般般,只有大于5时,她决定再看看。这就完成了错误的处理过程。

值得说一下的是,Herror的最后参数是一个可变形参,所以具有更大的灵活性,便于程序的扩展。其中可变形参的获取用到了va_start和va_end宏,这个宏在标准库<stdarg.h>中定义。详细的使用说明可以去网上搜一下。

 

C++的统一异常处理

 C++提供了异常处理的一个类:exception。为了解决我们自己碰到的异常,只需要继承这个类,并重载或自定义一些错误处理函数即可实现。同样是上面的列子,我们改动一下:

  1 #include <iostream>
  2 #include <cstdlib>
  3 using namespace std;
  4 #define COUNT 6
  5 static char *pall[]={"Ring", "Rose", "BMW", "Tall", "Rich", "Handsome"};
  6 
  7 typedef struct _Condition {
  8     char *pgift[COUNT];
  9     int ngift;
 10 }Condition;
 11 
 12 class MyException:public exception
 13 {
 14 public:
 15     MyException():m_ntype(-1),m_str(NULL) {}
 16     MyException(int n, char *p):m_ntype(n),m_str(p) {}
 17     char* Deal() const throw();
 18     ~MyException()
 19     {
 20         if(m_str)
 21         {
 22             delete m_str;
 23             m_str = NULL;
 24         }
 25     }
 26 private:
 27     int m_ntype;
 28     char *m_str;
 29 };
 30 static void Select(const Condition *con);
 31 
 32 int main(int argc, char **argv)
 33 {
 34     Condition A,B,C;
 35     Condition *pcon[3];
 36     memset(A.pgift, 0, COUNT);
 37     memset(B.pgift, 0, COUNT);
 38     memset(C.pgift, 0, COUNT);
 39     A.pgift[1]=pall[1]; A.ngift=1;//A->Rose
 40     B.pgift[0]=pall[0]; B.pgift[5]=pall[5]; B.ngift=2;//B->Ring,Handsome
 41     C.pgift[1]=pall[1]; C.pgift[2]=pall[2]; C.pgift[4]=pall[4]; C.ngift=3;//C->Rose,BMW,Rich
 42     pcon[0] = &A; pcon[1] = &B; pcon[2] = &C;
 43 
 44     for (int i=0; i<3; i++)
 45     {
 46         try
 47         {
 48             Select(pcon[i]);
 49         }
 50         catch (MyException &e)
 51         {
 52             char *ptemp;
 53             ptemp = e.Deal();
 54             if (ptemp!=NULL)
 55             {
 56                 printf("\n---------Result--------\n");
 57                 cout<<ptemp<<endl;
 58                 printf("\n----------over---------\n");
 59                 delete ptemp;
 60             }    
 61         }
 62     }
 63     return 0;
 64 }
 65 /*****************************************
 66 *根据条件考虑每个人,并调用错误统一处理函数
 67 ******************************************/
 68 static void Select(const Condition *con)
 69 {
 70     char *presult;
 71     if(con==NULL)
 72         return;
 73     if (NULL == (presult = new char[1024]))
 74     {
 75         exit(1);
 76     }
 77     switch(con->ngift)
 78     {
 79     case 0:
 80         break;
 81     case 1:
 82         sprintf(presult,"fail:only have %s",con->pgift[1]);
 83         throw MyException(1, presult);
 84         break;
 85     case 2:
 86         sprintf(presult,"fail:only have %s,%s", con->pgift[0], con->pgift[5]);
 87         throw MyException(2, presult);
 88         break;
 89     case 3:
 90         sprintf(presult,"fail:only have %s,%s,%s",con->pgift[1], con->pgift[2], con->pgift[4]);
 91         throw MyException(3, presult);
 92         break;
 93     default:
 94         break;
 95     }
 96 }
 97 char* MyException::Deal() const throw()
 98 {
 99     char *pstr = new char[1024];
100     if (pstr == NULL)
101         return NULL;
102     if(m_ntype < 3)
103         sprintf(pstr,"pass over:%s",m_str);
104     else if(m_ntype < 5)
105         sprintf(pstr,"just so so:%s",m_str);
106     else
107         sprintf(pstr,"wait and see:",m_str);
108     return pstr;
109 }

利用C++的try/catch/throw框架即可捕获异常,在把关的select函数中,我们有自定义的异常类MyException对象,将相关信息写进类中,然后抛出。在catch中捕获以后,调用类的Deal函数对异常进行统一处理。如果以后美女的想法改变,只有达到了5项条件的才算正常,那我们只需要修改Deal函数就可以了。