咱們今天來看下異常處理,在看 C++ 的異常處理以前,先來看看 C 語言中的異常處理。那麼什麼是異常呢?在程序運行過程當中可能會產生異常,異常(Exception)與 Bug 的區別是:異常是程序運行時可預料的執行分支,而 Bug 是程序中的錯誤,是不被預期的運行方式。ios
下來咱們來看看異常和 Bug 的對比:a> 異常好比運行時產生除 0 的狀況,須要打開的外部文件不存在,數組訪問時越界;b> Bug 是使用野指針,堆數組使用結束後未釋放,選擇排序沒法處理長度爲 0 的數組。在 C 語言中的經典處理方式爲:if ... else ... 。if 語句中處理的是正常狀況代碼邏輯,else 語句中處理的是異常狀況代碼邏輯。數組
咱們仍是以代碼爲例來看看除法操做異常的處理ide
#include <iostream> #include <string> using namespace std; double divide(double a, double b) { const double delta = 0.000000000000001; double ret = 0; if( !((-delta < b) && (b < delta)) ) { ret = a / b; } else { ret = 0; } return ret; } int main() { cout << divide(1, 1) << endl; cout << divide(1, 0) << endl; return 0; }
咱們看看編譯結果函數
執行的結果是正確的,可是若是咱們打印的是 0/1 的結果呢?咱們就不知道執行的究竟是正確的狀況仍是異常的狀況。那麼咱們在上面程序中的 divide 函數中添加一個參數,用來表示執行結果的正確與否,根據這個參數的值來判斷執行是否正常。程序以下學習
#include <iostream> #include <string> using namespace std; double divide(double a, double b, int* valid) { const double delta = 0.000000000000001; double ret = 0; if( !((-delta < b) && (b < delta)) ) { ret = a / b; *valid = 1; } else { *valid = 0; } return ret; } int main() { int valid = 0; double r = divide(1, 0, &valid); if( valid ) { cout << "r = " << r << endl; } else { cout << "Divided by zero..." << endl; } return 0; }
咱們來看看編譯結果spa
再來試試 0/1 呢指針
咱們看到結果已經正確的執行了。可是這個程序有個缺陷,即是 divide 函數須要 3 個參數,難以理解它的用法,並且 divide 函數調用後必須判斷 valid 表明的結果,當 valid 爲 true 時,運算結果正常;當 valid 爲false 時,運算結果出現異常。在 C 語言還有一種異常處理的方式,經過 setjmp() 和 longjmp() 進行判斷。下來咱們來說講這兩個函數的原型及其意思:a> int setjmp(jmp_buf env) 是將當前上下文保存在 jmp_buf 結構體中;b> void longjmp(jmp_buf env, int val) 從 jmp_buf 結構體中恢復 setjmp() 保存的上下文,最終從 setjmp 函數調用點返回,返回值爲 val;下來咱們經過示例代碼來進行分析排序
#include <iostream> #include <string> #include <csetjmp> using namespace std; static jmp_buf env; double divide(double a, double b) { const double delta = 0.000000000000001; double ret = 0; if( !((-delta < b) && (b < delta)) ) { ret = a / b; } else { longjmp(env, 1); } return ret; } int main() { if( setjmp(env) == 0 ) { double r = divide(1, 0); cout << "r = " << r << endl; } else { cout << "Divided by zero..." << endl; } return 0; }
在它進入 main 函數的 if 語句後,會將 0 保存在當前的 env 中,而後 setjmp 函數會保存當前的上下文信息。而後執行 divide 函數,進入到 divide 函數中,會進入到 else 分支。longjmp 函數則會將 1 保存到 env 中並將程序的執行流跳轉到 setjmp 處,此時 env 爲 1,所以條件不成立,因此會打印出 Divided by zero...,咱們來看看編譯結果圖片
咱們再來看看 1/1 呢,進入到 divide 函數中,它會執行 if 語句進行正常的計算以後直接便會返回 ret,便會輸出結果
開發
雖然這是兩個參數,可是它有必定的缺陷。setjmp() 和 longjmp() 的引入就必然涉及到使用全局變量,暴力跳轉致使代碼的可讀性下降,其本質仍是 if ... else ... 異常處理方式。它的暴力跳轉會破壞 C 語言的結構化特性(順序執行、選擇執行、循環執行)。C 語言中的經典異常處理方式會使得程序中邏輯混入大量的處理異常的代碼。正常邏輯代碼和異常處理代碼混合在一塊兒,致使代碼迅速膨脹,難以維護。那麼在 C++ 中確定便會有更好的異常處理方式,咱們後面會繼續學習。經過對 C 語言中異常處理的學習,總結以下:一、程序中不可避免的會發生異常;二、異常是在開發階段就能夠預見的運行時問題;三、C 語言中經過經典的 if ... else ... 方式處理異常,在 C++ 中存在更好的異常處理方式。
歡迎你們一塊兒來學習 C++ 語言,能夠加我QQ:243343083。