使用C++異常來取代exit()函數[1]

字號:

從C語言開始接觸C++的人,恐怕都知道exit()這個函數,似乎現在很多的程序員都有這樣一種習慣,在程序一遇到錯誤、或任務剛完成時,把調用exit()函數當成是一種的結束程序的方法。在以前遺留的許多老式C/C++代碼中,這種現象非常普遍,但當手頭的軟件項目逐步進展并越來越大時,就不得不面臨合并以前分散的各個模塊這項工作,此時,如果還有人記得起軟件日志記錄、錯誤寬容度、或至少適當的清理工作,就已經是萬幸了。本文中要說的方法,決不是一條設計準則,但是可減輕修正那些未良好設計及實現的老式代碼時所帶來的痛苦。
    用return來取代exit,無疑是解決此問題最顯而易見的方法,如果軟件項目非常簡單,這也是效的解決方案;然而,項目中經常有成打的函數分布在多個源文件中,且這些函數的調用也嵌套在很深的層次中,那么,事情就變得棘手了。如果在這種情況中,所有的函數都返回void,還是有可能修改它們,讓其返回一個退出碼(exit code)的,但所付出的代價也很大;如果函數已經能返回一個有意義的值,只是在遇到錯誤時,調用了exit(),那么這項工作會變得更消耗時間,也會更加容易出錯。這里說點題外話,使用exit()也是有可取之處的,當老式代碼沒有設計返回任何東西時,如果想得到返回碼(return code),只有靠exit()了。
    有關此問題,還是有一個解決方法的,在這種情況下,我們假定所有的源代碼已經為C++格式,或無需全部編譯就可以移植為C++格式,把所有exit出現的地方全部換成throw(這可以自動完成,甚至無須理解老代碼是怎樣工作的);接著,在任何適當的地方,捕捉為整數的異常碼,這種方法還可依據嚴重性或恢復程度的不同,在不同層面上處理錯誤。
    請看以下示例,原始代碼如下:
    // main.cpp
    void main() {
    //初始化
    ...
    ProcessMail(...);
    }
    //另一個源文件
    void ProcessMail(...) {
    //初始化
    ...
    if ( initializationError ) {
    printf("faild to init!!!\n");
    exit(-1);
    }
    while ( !shutdown ) {
    ReadMail(...)
    //繼續(xù)處理
    ...
    }
    }
    void ReadMail(...)
    {
    ...
    //對ReadBytes()的調用出現在函數內的多處地方,包括在循環(huán)中。
    nBytesAvailable = ReadBytes(...)
    ...
    }
    //另一個源文件
    int ReadBytes(...)
    {
    //讀取數據
    ...
    if ( error ) {
    printf("there was an error!!\n");
    exit(-1);
    }
    return nBytesRead;
    }