1. 程式人生 > >c++異常處理(以處理除0錯誤為例)

c++異常處理(以處理除0錯誤為例)

一、概念

異常處理的優勢: 

將程式邏輯&錯誤處理邏輯混在一起,會降低程式效能。如果沒有異常發生,異常處理程式碼對效能的影響很小。更有效。

異常處理將錯誤處理從程式執行的“主線”中剝離出來,提高程式的清晰性,增強可修改性。程式設計師可以處理任何異常——所有異常、某種型別的所有異常 或 一組相關型別的所有異常(即通過繼承層次相聯絡的異常型別)。減少錯誤的可能性,是程式更健壯。

異常處理必需品

定義異常類,表示可能出現的問題型別(見程式碼)

在try程式碼塊中包含程式碼

try程式碼塊由關鍵字try以及後面的一對大括號組成大括號中定義的程式碼塊,就是可能出現異常的程式碼。try程式碼塊中包含了可能引起異常的語句以及發生異常時應該跳過的語句。(也就是可能引起異常的函式以及沒有異常發生時應該執行的語句

異常可能是由try程式碼塊中的程式碼直接導致的,也可能是由於呼叫其它函式導致的,還有可能是由於try程式碼塊中的程式碼所發起的深層巢狀函式呼叫所導致的。

定義catch處理器,處理DivideByZeroException異常

異常是由catch處理器處理的,他會捕獲並處理異常在每個try程式碼塊之後,必須至少緊挨著一個catch處理器。每個catch處理器都以關鍵字catch開始,並在一對圓括號中指定一個異常引數(exception parameter),表示它能夠處理的異常的型別(DivideByZeroException)。當try程式碼塊發生異常時,就會執行異常引數的型別與這個異常匹配的那個catch處理器

(即catch程式碼塊的型別與被丟擲的異常型別準確對應,或者是他的基類)。如果異常引數包含可選的引數名,則catch處理器可以使用這個引數名與catch處理器程式碼體重被捕獲的異常互動(不理解)

catch捕獲到異常後通常要乾的事:向用戶報告錯誤,在檔案中記錄日誌,從容的終止程式,嘗試用其他策略完成這個失敗的任務。

catch 以引用的形式捕獲異常物件,消除了複製表示被丟擲異常物件的開銷。

異常處理的終止模型(即程式如何執行)

如果try程式碼塊中的語句產生了異常,則這個try程式碼塊就會立即終止。程式會搜尋能夠處理這種異常型別的第一個catch處理器。catch到達他的右大括號,異常處理完畢。catch處理器中定義的區域性變數(包括它的異常引數)便離開了作用域。程式控制並不返回異常發生的那一丟擲點。

控制將在try程式碼塊下面的最後一個catch處理器後的第一條語句恢復執行。

如果try程式碼塊沒有發現異常,則程式會忽略所有catch處理器,而程式的控制會在這個try程式碼塊下面的最後一個catch處理器之後的第一條語句繼續。

如果try程式碼塊產生了異常,但不存在匹配的catch處理器,或者異常發生在try程式碼塊外部的語句裡,則包含這條語句的函式會立即終止,程式會嘗試在呼叫函式中找到一個外層try程式碼塊。——堆疊解退(詳見後)

何時使用異常處理

異常處理專門用於應付在執行語句時發生的同步錯誤。常見例子:陣列下標越界、算術溢位(即值位於可表示的範圍之外)、除零、無效的函式引數以及不成功的記憶體分配(記憶體不夠)。

異常處理不使用處理與非同步事件。例子:磁碟I/O完成、網路訊息到達、滑鼠單擊、鍵擊。這些是與程式的控制流平行的或獨立的。

包含常見錯誤條件的函式,應該返回0或NULL(或其他合適的值),而不是丟擲異常。呼叫這種函式的程式,可以檢查函式的返回值,以判斷函式呼叫是否成功。

重拋異常

異常處理器接收到異常時,可能無法處理這個異常,或者只能處理這個異常的一部分。此時,異常處理器可以將異常處理(或者其中的一部分)推送給另一個異常處理器。通過語句:

 throw;

重拋異常。不管異常處理其是否能夠處理(甚至是部分處理)異常,他都能夠重拋這個異常。在他的外面進行進一步處理。下一個try程式碼塊會檢測到這個重拋的異常,在後面的catch處理器會嘗試處理這個異常。

#include<iostream>

using std::cout;

usign std::endl;

#include<exception>

using std::exception;

// throw ,catch and rethrow exception

void throwException(){    // throw exception and catch it immediately

try{

cout<<" Function throwException throws an exception/n";

throw exception();     // generate exception

}catch( exception &){    // handle exception

沒有在這個例子的catch處理器中使用異常引數,因此省略了異常引數名,至指定了要捕獲的異常型別

cout<<" Exception handled in function throwException"

  <<"/n Function throwException rethrows exception ";

   throw;      // rethrow exception for further processing

// end catch

cout<<"This also should not print/n";

// end function throwException

int main(){

try{  // throw exception

       cout<<"/nmain invokes function throwException/n";

        throwException();

        cout<<"This should not print/n "; }   // end try

catch( exception & ){ // handle exception    

cout<<" /n/nException handled in main/n";}   //  end catch

cout<<"Program control continues after catch in main/n";

return 0;

} // end main

二、常見程式設計錯誤:

1、try程式碼塊與對應的catch處理器之間,或者在它的幾個catch處理器之間放置程式碼——語法錯誤

2、每個catch處理器只能有一個引數,如果指定了一個逗號分隔的異常引數表——語法錯誤

3、在一個try程式碼塊之後的兩個不同的catch處理器中捕獲同一種類型的異常——邏輯錯誤

4、在catch處理器的外面執行一條空的throw語句,會導致呼叫terminate函式,他會放棄異常處理,並立即終止程式。