首页 > 代码库 > 程序设计中关于异常机制的思考

程序设计中关于异常机制的思考

    程序的运行过程从来都不是一帆风顺的,运行期间会遇到各式各样的突发状况,如文件打不开、内存分配错误、数据库连不上等等。作为一个进阶过程中的编程人员,思考和处理例外状况极为重要。因为它在很大程度保证了程序的连贯性和稳定性,并为问题的发现提供支撑。

    下面就本人在编程过程中有关异常的编程范式做一下总结。


一、面向过程形式


    面向过程式的范式将异常的传递都交于函数的参数与返回值来处理,如:

bool func ( const InType& input, OutType& output, string& errMsg );

在函数中func中,bool类型的返回值用于标明函数的运行结果是否有异常,input是函数输入,output是函数的运行结果的引用,errMsg是异常信息的引用。output和errMsg都是用于向func函数的调用者传递信息。

    当函数存在异常时,异常的信息就被保存在errMsg中,此外errMsg中还可以加上出现此异常的位置信息,例如异常出现在哪个函数中;而没有发生异常时,errMsg只需要单纯的加上此时的位置信息即可。这样,一旦发生异常,异常信息就会如同一个堆栈那样被传到最上层的调用者那里。如:

//定义三个用于嵌套调用的函数
bool func1 ( const InType& input, OutType& output, string& errMsg )
{
    ...
    
    //此处出现异常
    if(hasException())
    {
        //异常处理
         handleException();
        errMsg += "func1:Error occurs->";
        return false;   
    }
    
    ...
}
bool func2 ( const InType& input, OutType& output, string& errMsg )
{  
    ...
    
    //此处调用func1
    if(!func1(input, output, errMsg))
    {
         //异常处理
         handleException();
         errMsg += "func2:Call func1 Error->"
         return false;   
    }
    
    ...
}
bool func3 ( const InType& input, OutType& output, string& errMsg )
{
    ...
    
    //此处调用func2
    if(!func2(input, output, errMsg))
    {
         //异常处理
         handleException();
         errMsg += "func3:Call func2 Error->"
         return false;   
    }
    
    ...
}


// 客户端调用函数
void call()
{
    ...
    
    //此处调用func3
    if(!func3(input, output, errMsg))
    {
         //异常处理
         handleException();
         errMsg += "call:Call func3 Error"
         print errMsg;  
    }
    
    ...
}

此时,输出的错误信息为:

func1:Error occurs->func2:Call func1 Error->func3:Call func2 Error->call:Call func3 Error

这样错误栈就这样展示出来了。


二、面向对象形式


    面向对象语言一般都自带有异常处理机制,通常为Exception类。若出现异常,可以就近处理,也可以向上级调用函数抛出。

    笔者刚接触面向对象时,曾经非常不理解其异常机制存在的理由,认为它很鸡肋。现在随着对编程理解的深入,越来越觉得这种异常机制的强大之处,尤其是对大型系统而言。

    首先,异常被封装成了对象,可以自己定义,不必像面向过程的形式那样都表现为字符串。

//异常类的定义
class Exception{
public:
    Exception(const string& errMsg):m_errMsg(errMsg){}
    
    string errMsg(){
        return m_errMsg;
    }
private:
    string m_errMsg;
};

class Exception1:public Exception{...}

class Exception2:public Exception{...}

class Exception3:public Exception{...}

    其次,一个函数可以抛出多个异常,同样外层调用函数也可以同时捕捉多个异常。

//抛出异常的函数
OutType func(InType input)
{
        ...
    
    //此处出现异常
    if(hasException1())
    {
        //异常处理
        handleException1();
        string errMsg = "Exception1 occurs";
        throw Exception1(errMsg );   
    }
    
    ...
        if(hasException2())
    {
        //异常处理
        handleException2();
        string errMsg = "Exception2 occurs";
        throw Exception2(errMsg );   
    }
    
    ...
        if(hasException3())
    {
        //异常处理
        handleException3();
        string errMsg = "Exception3 occurs";
        throw Exception3(errMsg );   
    }
    
    ...
    return output;
}

// 外层调用函数
void call()
{
    ...
    try{
        //调用 func 函数
        OutType output = func(input);
        
    }catch(Exception1 e1){
        handleException(e1);
        print e1.errMsg();
    }catch(Exception1 e2){
        handleException(e2);
        print e2.errMsg();
    }catch(Exception1 e3){
        handleException(e3);
        print e3.errMsg();
    }
    ...
}

    最后,这种异常机制将函数的参数和返回值从异常的传递任务中解放了出来,函数不必再通过参数返回错误信息,返回值也可以返回这个函数真正的调用结果,而不用向面向过程的形式那样返回是否有异常。


本文出自 “仲梓源的技术博客” 博客,请务必保留此出处http://zhongziyuan.blog.51cto.com/3450270/1529882