断言、错误、异常、返回值、错误码等理解

1. ********断言********
 
_ASSERT主要用在同一个开发小组内部编程中,它用来限定开发者在调用别人的
函数时,要遵守被调用函数的前条件、后条件、不变式。可见,断言的使用是为了
缩小调用范围,给同一个小组的开发人员以一个友好的提示。

2. ********错误的分类与处理方法********

(1)操作员与人机交互错误(不满足规则的操作,是可恢复的)
 
 程序检验、提示规则
 
(2)运行时错误(网络、文件系统、数据库、其它业务引用系统)

 记录并抛出异常,或返回错误码

(3)程序员错误与客户模块交互

 使用断言

3. ********异常的处理方式********

(1)同步调用

     1)对对有能力处理的异常,捕获并处理之

     2)对原始信息过于技术化的异常,捕获并包装之,重新抛出

     3)在调用的中间层,对未知异常保持沉默

     4)在调用的最高层,必须捕获所有异常,避免本身进程或宿主进程崩溃

(2)异步调用

     1)异步调用一般不应有任何返回值

     2)服务方最好以同样的方式返回正常信息和错误信息,即正常信息是通过通知的
        方式返回的话,错误信息也应该通过通知的方式返回;正常信息是通过主动查
        询得到的话,错误信息也应该通过主动查询得到。

4. ********异常处理规范********

*异常应该是分层的*

(1)异常定义

     1)每个模块应该有自己的应用程序异常类型层次,从本模块主动抛出的应用程序异常
        都应该属于该异常类型层次,客户代码可以只捕捉该层次的基类(?)     

     2)应用程序的所有自定义异常都应该从开发平台提供的“应用程序异常基类”派生  

     3)中间件等平台程序的运行时异常都应该从开发平台提供的“运行时异常基类”派生(?)

     4)中间件等平台程序的运行时错误都应该从开发平台提供的“错误基类”派生(?)

(2)异常捕获
    
     1)对有能力处理的异常,捕获并处理之

     2)在调用的中间层,对未知异常保持沉默

     3)在调用的最高层,必须捕获所有异常,避免本身进程或宿主进程崩溃

     4)记录捕获到的每个原始异常的信息

(3)异常抛出
    
     1)每个模块应使用本模块所能得知的最精确的错误原因报告异常信息

     2)如果有原始异常,在重新抛出的自定义异常中附加原始异常的信息

5. ********几点说明********

(1)错误处理与日志系统

     1)错误处理不等同于日志系统,日志系统只是错误信息的一种记录手段
   
     2)错误信息的输出应全部调用日志系统来完成

(2)程序员错误与运行时错误

     1)接口函数的前置条件,应该是一种规范,是客户程序员必须遵守的约定;客户程序员违反了
        约定,程序将产生异常或不可预知的错误;对于这类约定,不应该需要有运行时的代码检查;
        比如如果你的接口函数的一个参数不能为null,而你在函数开始部分程序里写:

        if(xxx == null)
            throw new someException();

        你的代码实际上允许该参数为null,因为你对null的情况进行了运行时处理;尽管你在文档里
        声明该参数不能为null,但如果客户程序员遵守了约定,那么你这段检查代码就是冗余的。

     2)当你对参数没有任何检查就进行了使用,而非法的参数值导致了错误,此时有两种情况:
 
        1...如果你在接口函数说明里列出了参数不允许的非法取值,那么客户程序员应该修改程序避免传入
        非法值,该类错误称为程序员错误;

        2...如果你没有说明,那么你应该修改函数,处理非法参数。

     3)不是所有的限制条件在文档里说明一下,就可以把责任扔给客户程序员了,有一些错误必须处理:
        特别是客户程序员不需要import你的package就可以和你的接口交互的情况,如socket服务器 ,
        你必须在socket服务程序内部检查所有接收到的数据,拒绝错误的请求,否则极易遭到攻击 。

(3)错误代码与异常
    
     1)不应该使用bool值来返回成功与否,bool返回值只应用在真正查询bool状态的操作中,
        如 bool IsDirty(),bool hasNext()等。
 
     2)整形或bool型的错误代码返回值强迫客户程序员检查每一次调用,应用异常取代之 。

6. ********一个函数调用多个子函数时,发生错误的理解********

(1)当后续的子函数发生错误时,前面执行的函数又改变了类的状态,在返回错误码之前,需要回滚状态吗?

答案:不需要回滚。只需要考虑、确定“如果主函数失败,总体上应该怎样处理?”,譬如,这个错误是可以
            恢复的,或者不可恢复直接delete这个对象,那么只需要在“后续的某个步骤上处理掉回滚”即可。

(2)当涉及分配资源时,如果失败怎么办?

答案:同样不需要马上回滚,只需在后续的某个步骤上处理掉即可。如果处理不掉,程序就强制退出。(在
MSDN上CreateEvent失败时,程序会ExitProcess)。因此,在析构函数中,如果某些资源释放不掉,就不
要抛出异常了。析构函数里不能抛出异常,另外,即使抛出,外围也没办法处理(因为同样释放不掉)。

(3)返回值需要封装吗?

答案:根据功能分解的要求,每个小函数都是一个功能单元。当一个大函数调用这些小函数时,可能发生多个
      分配资源失败,如new, createobject等,这些失败的返回值可以统一成“分配失败错误”;对多个不了
      解细节的错误,返回值可统一成“ERROR_UNKNOWN”;对于具体技术细节的错误,可以把返回值“原样
      返回”;
 
      当这个大函数被调用时,就可以根据“这些经过转换、包装、统一后的返回值”,进行不同方式的处理,如:
      继续往上层返,走同一层次的其它路径,发异常,弹对话框等。
     
      ****************************************************************************************************************
      * 对此问题产生迷惑的真正原因是:没有真正理解“Decompose”,须知“功能分解”就是功能的封装,*
      * 对于“封装”而言,它本身就是一个“实体”,它会接受什么“输入”?返回几种“输出”?在封装       *
      * 之前,就应该是确定下来的了!所以要充分理解这个“功能实体”的含义!                                                   *
      ****************************************************************************************************************

(4)函数调用分层时,各层都要打log吗

答案:太小的函数或类(功能单元)不需要打log,大一点的要打log,log可以层层往上打。同样返回值也可以
      层层往上返,但要注意适当的“转换、包装、统一”。 总之,要充分理解“功能分解”。   

7. ********返回值封装与层层打log的再沉思心得********

(1)每一个类都可以安排一个enum集,表示该类所有需要返回的状态码。这样,如果用多个这样的“小类”组合
     成一个“大类”时,“小类”的成员函数会被调用,需要判断它返回的“状态码”。这时,根据“大类”
     功能分解,就会需要对“小类的返回状态码”进行语义上的再次封装。如果想把“小类的返回状态码”完整
     的体现出来,则需要一个“小类的返回状态码”和“大类的返回状态码”的一一对应“映射表”。如果这样
     做,对“大类”而言,就是相当于“简单的组合”了“所有小类的返回状态码”。很徒劳!问题是,“大类”
     需要用到“小类”所有的返回码吗?
    
     这要视“大类”的“功能设计”而定。如果“大类”一一判断“小类”的返回值,并作出可以弥补的修改,
     则返回值的“一一映射”就不必要了,需要更高层次的语义转换。

(2)对开发者而言,所有自己编写模块的返回值,可以共用一个enum集。这样,即使函数调用涉及返回值,也只
     需要直接返回即可。既然大小模块都是同一个人(team)开发,而且“大模块”又包含了“小模块”,那么
     就是说,可以把“大模块”看作一个“整体”,共用一个enum集当然理所当然!!其实哪里有所谓的“小模
     块”呢?它仅仅就是“大模块”的一部分嘛!!!

(3)层层打log的问题。

     1、一般地,非外部接口函数,没必要打;
     2、不出现错误、状态转换、大的外部数据交换,没必要打;
     3、关于同一个问题(错误、状态变换)的log,在这个模块内,没必要打多次,只打一次即可;
     4、对于外部调用打出的log,如果和模块内的log重复,则没办法、也没必要干涉。     
 

你可能感兴趣的:(C++学习笔记)