天天看點

異常處理

一、關鍵點

異常:存在于運作時的反常行為,這些行為超出了函數正常功能的範圍。

典型的異常:失去資料庫連接配接、遇到意外輸入等。

異常處理機制:為程式中異常檢測和異常處理這兩部分的協作提供支援。

二、異常檢測

形式:throw 表達式;

解釋:上面的語句将引發(或抛出)一個異常,其中表達式的類型就是抛出的異常類型。

示例:throw runtime_error("自定義提示語");    //類型runtime_error就是一種異常類型

類型runtime_error:是标準庫異常類型中的一種,定義在stdexcept頭檔案中。我們必須初始化runtime_error的對象,方式是給它提供一個string對象或一個字元串字面值,這個字元串主要寫一些關于異常的輔助資訊。

————————————————2017-11-7更新補充————————————————

補充1:表達式不僅僅隻有一個異常類型(也就是抛出對象的類型),還包括抛出對象的内容,如throw runtime_error("除數不能為0"),其中标紅的地方就是抛出對象的内容。

補充2:throw語句執行完,就轉到對應的catch語句,而非繼續執行throw語句之後的語句。

補充3:異常對象,編譯器使用異常抛出表達式來對異常對象進行拷貝初始化(這是另一種抛出異常的形式:range_error r("errpr"); throw r;)

補充4:當異常處理完畢後,異常對象被銷毀(是以,如果異常抛出表達式是類類型的話,則相應的類必須含有一個可通路的析構函數)

——————————————————補充完畢———————————————————

三、異常處理

1. try語句塊

文法形式:

解釋:try語句塊中的program-statements組成程式的正常邏輯,像其他任何塊一樣,program-statements可以有包含聲明在内的任意C++語句。隻是在try語句塊内聲明的變量在塊外無法通路,即使是catch子句也無法通路。

2. catch子句

包括三部分:關鍵字catch、括号内一個(可能未命名的)對象的聲明(稱作異常聲明)、一個語句塊

多個catch子句:當選中了某個catch子句處理異常之後,執行與之對應的塊。

catch子句完成:程式跳轉到最後一個catch子句之後的那條語句繼續執行。

補充1:若找到一個比對的catch子句,則程式進入該子句并執行其中的代碼

補充2:當執行完這個catch子句後,找到與try塊關聯的最後一個catch子句之後的點,并從這裡繼續執行

補充3:異常聲明的類型決定了處理代碼所能捕獲的異常類型

補充4:進入一個catch語句後,通過異常對象初始化異常聲明中的參數

補充5:異常的類型和catch聲明的類型的比對規則:①允許從非常量向常量的類型轉換,即一個非常量對象的throw語句可以比對一個接受常量引用的catch語句;②允許從派生類向基類的類型轉換;③數組被轉換成指向數組(元素)類型的指針,函數被轉換成指向該函數類型的指針

補充6:捕獲所有異常的catch語句,形如catch(...),可以與任意類型的異常比對

四、尋找處理代碼的辛酸過程

1. try語句塊可能調用了包含另一個try語句塊的函數:使得程式在遇到抛出異常的代碼前,其執行路徑可能已經經過了多個try語句塊。

2. 尋找處理代碼的過程:當異常被抛出時,程式首先搜尋抛出該異常的函數,如果在目前函數沒找到比對的catch子句,就終止該函數,并在調用該函數的函數中繼續尋找。

3. 标準庫函數terminate:負責終止程式的執行過程,即程式最終都沒找到比對的catch子句,就執行該函數讓程式非正常退出。

4. 沒有定義try語句塊:此時發生異常,系統會調用terminate函數并終止目前程式的執行。

補充1:當抛出一個異常後,程式(暫停目前函數的執行過程)立即開始尋找與異常比對的catch子句

補充2:棧展開過程,沿着嵌套函數的調用鍊不斷查找,直到找到了與異常比對的catch子句為止(或者也可能一直沒找到比對的catch,則退出主函數後查找過程終止)

  當throw出現在一個try語句塊内時,檢查與該try塊關聯的catch子句:

  1)找到了比對的catch,就使用該catch處理異常

     2)未找到比對的catch,

    ①該try語句嵌套在其他try塊中,則繼續檢查與外層try比對的catch子句

      1° 還是找不到比對的catch,則退出目前的函數,在調用目前函數的外層函數中繼續尋找

補充3:若找到比對的catch并執行完該catch,程式跳轉到與try塊關聯的最後一個catch子句之後的那條語句繼續執行,這表明了可能會跳過許多函數、語句塊

五、異常類

1. 作用:報告标準庫函數遇到的問題,異常類也可以用在使用者編寫的程式中。

2. 定義異常類的4個頭檔案:

頭檔案名稱

說明

exception

定義了最通用的異常類exception,它隻報告異常的發生,不提供任何額外資訊

stdexcept

定義了幾種常用的異常類:exception、runtime_error、range_error等

new

定義了bad_alloc異常類型

type_info

定義了bad_cast異常類型

3. 頭檔案stdexcept中定義的異常類

異常類

錯誤類型

最常見的問題

runtime_error

隻有在運作時才能檢測出的問題

range_error

運作時錯誤:生成的結果超出了有意義的值域範圍

overflow_error

運作時錯誤:計算上溢

underflow_error

運作時錯誤:計算下溢

logic_error

程式邏輯錯誤

domain_error

邏輯錯誤:參數對應的結果值不存在

invalid_error

邏輯錯誤:無效參數

length_error

邏輯錯誤:試圖建立一個超出該類型最大長度的對象

out_of_range

邏輯錯誤:使用一個超出有效範圍的值

4. 異常類定義的幾種運算:建立或拷貝異常類型的對象、為異常類型的對象指派

5. 不能被提供初始值的對象:exception、bad_alloc、bad_cast對象,它們隻能以預設初始化的方式來初始化

6. 不能使用預設初始化的對象:除了上面的對象,其他對象在建立時必須提供初始值(string對象或字元串字面值),該初始值含有錯誤相關的資訊

7. 異常類的成員函數:隻有一個名為what的成員函數,該函數傳回值是一個const char *(字元串字面值),目的是提供關于異常的一些文本資訊。該字元串的内容與異常對象的類型有關,如果異常類型有一個字元串初始值,則what傳回該字元串。而對于無初始值的異常類型來說,what傳回的内容由編譯器決定。

六、示例

題目:編寫一個程式,從标準輸入讀取兩個整數,輸出第一個數除以第二個數的結果。要求:當第二個數是0時抛出異常,使用try語句塊去捕獲異常,catch子句應該為使用者輸出一條提示資訊,詢問是否輸入新數并重新執行try語句塊的内容。

代碼:

異常處理

View Code

七、小結

一句話:try是檢測異常的,如果産生了異常,就throw(抛出)一個異常,然後被catch到,在catch塊中進行異常的處理。