官术网_书友最值得收藏!

1.3 C++異常處理

程序中的錯誤通常包括:語法錯誤、邏輯錯誤和運行時異常(Exception)。其中,語法錯誤通常是指函數、類型、語句、表達式、運算符或標識符的使用不符合C++中的語法,這種錯誤在程序編譯或連接時就會由編譯器指出;邏輯錯誤是指程序能順利運行,但是沒有實現或達到預期的功能或結果,這類錯誤常需要通過調試或測試才能發現;運行時異常是指在程序運行過程中,由于意外事件的發生而導致程序異常終止,如內存空間不足、打開的文件不存在、零除數、下標越界等。

異常或錯誤的處理方法有很多,如判斷函數返回值、使用全局的標志變量、直接使用C++中的exit()或abort()函數來中斷程序的執行。

1.3.1 使用C++異常處理

程序運行時異常的產生雖然無法避免,但可以預料。為了保證程序的健壯性,必須在程序中對運行時異常進行預見性處理,這種處理稱為異常處理。

C++提供了專門用于異常處理的一種結構化形式的描述機制try/throw/catch。該異常處理機制能夠把程序的正常處理和異常處理邏輯分開表示,使得程序的異常處理結構清晰,通過異常集中處理的方式,解決異常處理的問題。

1.try語句塊

try語句塊的作用是啟動異常處理機制,偵測try語句塊中的程序語句執行時可能產生的異常。如有異常產生,則拋出異常。try的格式如下:

注意:try總是與catch一同出現,在一個try語句塊之后,至少應該有一個catch語句塊。

2.catch語句塊

catch語句塊用來捕捉try語句塊產生的異常或用throw拋出的異常,然后進行處理,其格式如下:

其中,catch中的形參類型可以是C++基本類型(如int、long、char等)、構造類型,還可以是一個已定義的類的類型,包括類的指針或者引用類型等。如果在catch中指定了形參名,則可像一個函數的參數傳遞那樣將異常值傳入,并可在catch語句塊中使用該形參名。例如:

        try
        {
            throw "除數不能為0!";
        }
        catch(const char * s)                   // 指定異常形參名
        {
            cout<<s<<endl;                      // 使用異常形參名
        }

注意:

(1) 當catch中的整個形參為“”時,則表示catch能捕捉任何類型的異常。

(2) catch前面必須是try語句塊或另一個catch塊。正因如此,在書寫代碼時應使用這樣的格式:

        try
        {
            …
        } catch(…)
        {   …
        } catch(…)
        {   …
        }

3.throw

throw用來強行拋出異常,其格式如下:

其中,異常類型表達式可以是類對象、常量或變量表達式等。

4.三者關系和注意點

throw和catch的關系就好比函數調用關系,catch指定形參,而throw給出實參。編譯器將按照catch出現的順序及catch指定的參數類型確定throw拋出的異常應該由哪個catch來處理。

throw不一定出現在try語句塊中,實際上,它可以出現在任何需要的地方,即使在catch中的語句塊中,仍然可以繼續使用throw,只要最終有catch可以捕獲它即可。例如:

        class Overflow
        {   // ...
        public:
            Overflow(char,double,double);
        };
        void f(double x)
        {   // ...
            throw Overflow('+',x,3.45e107);// 在函數體中使用throw,用來拋出一個對象
        }
        try
        {   // ...
            f(1.2);
            // ...
        } catch(Overflow& oo)
        {
            // 處理Overflow類型的異常
        }

當throw出現在catch語句塊中時,通過throw既可以重新拋出一個新類型的異常,也可以重新拋出當前這個異常,在這種情況下,throw不應帶任何實參。例如:

        try
        {   ...
        } catch(int)
        {
            throw "hello exception";        // 拋出一個新的異常,異常類型為const char*
        } catch(float)
        {
            throw;                           // 重新拋出當前的float類型異常
        }

1.3.2 嵌套異常和棧展開

在C++中,異常處理嵌套一般指下列結構:

當然,在程序代碼中,若一個函數中的異常處理語句塊中還有另一個函數的調用,而另一個函數本身也會產生異常,這樣,通過函數嵌套調用也會形成異常處理嵌套。

在嵌套異常情況下,最底層函數所拋出的異常首先在內層中依次查找相匹配的catch語句塊,只要遇到第一個匹配的catch子句,查找就會結束,然后進入該catch子句,進行處理。若沒有匹配,則內層函數產生的異常逐層向外傳遞,最后回到主程序中。這種因發生異常而逐步退出復合語句或函數定義的過程,稱為棧展開(stack unwinding)過程。

需要說明的是:

(1) 隨著棧展開,在退出的復合語句和函數定義中聲明的局部變量的生命期也結束了。在棧中分配的局部變量所占用的資源也被釋放,由系統回收。但是,如果函數動態分配過內存或其他資源(包括用new運算符取得的資源和打開的文件)出現異常,這些資源的釋放語句可能被忽略,從而造成這些資源將永遠不會自動釋放。

(2) 在棧展開期間,當一個復合語句(或語句塊)或函數退出時,若遇到的局部變量是類對象時,則棧展開過程將自動調用該對象的析構函數,完成資源的釋放。

主站蜘蛛池模板: 长治市| 织金县| 阳山县| 临洮县| 蕲春县| 弥渡县| 北宁市| 阿克陶县| 奇台县| 六盘水市| 咸宁市| 阿尔山市| 民乐县| 镇平县| 甘孜| 兴化市| 上犹县| 澄城县| 仪征市| 洛川县| 东山县| 会宁县| 桐梓县| 新蔡县| 高台县| 汝州市| 彭阳县| 平安县| 含山县| 苍溪县| 丁青县| 长春市| 湖北省| 长顺县| 和林格尔县| 鄂州市| 正安县| 城口县| 武鸣县| 惠东县| 桓台县|