異常,當一個函數發現一個沒法處理的錯誤時拋出異常,讓函數的ios
調用者直接或間接的處理這個問題。 數組
異常處理,是一種容許兩個獨立開發的程序組件在程序執行期間遇到程序不正常的ide
狀況(稱爲異常,exception )時相互通訊的機制。函數
異常拋出:spa
throw (表達式)
異常發現與拋出異常:指針
/*發現異常而且拋出異常*/ try { //可能出現異常的語句 }
捕獲異常:orm
catch(類型名 + 形參名) //捕獲特定類型異常 { }
catch(...) //捕獲任意類型異常(在不肯定異常類型時使用) { }
下來看一個簡單的例子:對象
#include<iostream> using namespace std; int Div(int a, int b) { return a/b; } int main() { Div(1,0); system("pause"); return 0; }
結果顯示:blog
程序直接崩潰,因爲調用時傳入第二個參數是零,零不能做除數,因此會崩潰,下面使用異常處理這個問題:內存
#include <iostream> #include <string> using namespace std; int Div(int a, int b) { if(b == 0) { throw string("parameter error.");//異常拋出 } return a/b; } int main() { try { Div(1, 0);//發現異常,與拋出異常 } catch(const string& S) { cout<<S<<endl;//捕獲異常 } system("pause"); return 0; }
程序能夠正常運行,也能夠看到異常出現的地方,這樣就能夠很清楚的解決這個問題。
下面再看個了例子:
#include <iostream> #include <string> using namespace std; void test() { int* p = new int(1); if(1) { throw string("error."); } delete p; } int main() { try { test(); } catch(const string& S) { cout<<S<<endl; } system("pause"); return 0; }
結果顯示:
這個程序運行貌似沒有問題,其實問題大了。
void test() { int* p = new int(1); if(1) { throw string("error."); //程序執行到這裏,直接就去catch()那塊了, //致使new出來的內存沒有釋放,形成內存泄漏。 } delete p; }
內存泄漏:
會致使你開闢出來的那塊內存之後就不能夠用了,這樣多泄漏幾回,你的電腦就哈哈了,會很卡,很卡。
內存泄漏危害:
從用戶使用程序的角度來看,內存泄漏自己不會產生什麼危害,做爲通常的用戶,根本感受不到內存泄漏的存在。真正有危害的是內存泄漏的堆積,這會最終消耗盡系統全部的內存。從這個角度來講,一次性內存泄漏並無什麼危害,由於它不會堆積,而隱式內存泄漏危害性則很是大,由於較之於常發性和偶發性內存泄漏它更難被檢測到。
固然,這裏並非說內存泄漏,下面能夠用異常來處理上面這個問題:
#include <iostream> #include <string> using namespace std; void test() { int* p = new int(1); try//發現異常 { if(1) { throw string("error.");//異常拋出 } } catch(...)//捕獲異常 { delete p;//釋放開闢的空間 throw;//異常從新拋出 } delete p; } int main() { try//發現從新拋出的異常 { test(); } catch(const string& S)//捕獲異常 { cout<<S<<endl; } system("pause"); return 0; }
結果顯示:
這樣就不會出現內存泄漏,也會很清楚的在控制檯顯示錯誤的信息。
異常從新拋出:在異常處理過程當中也可能存在單個catch 子句不能徹底處理異常的狀況。在某些修
正動做以後,catch 子句可能決定該異常必須由函數調用鏈中更上級的函數來處理那麼catch子句能夠經過從新拋出(rethrow )該異常把異常傳遞給函數調用鏈中更上級的另外一個catch子句,rethrow 表達式的形式爲:
throw;
rethrow 表達式從新拋出該異常對象rethrow 只能出如今catch 子句的複合語句中。被從新拋出的對象就是其原來的異常對象。
棧展開:
在查找用來處理被拋出異常的catch 子句時由於異常而退出複合語句和函數定義這個過程
拋出異常的時候,將暫停當前函數的執行,開始查找對應的匹配catch語句。首先檢查throw自己是否在catch塊內部,若是是,再查找匹配的catch語句。若是有匹配的,則處理。沒有則退出當前函數棧,繼續在調用函數的棧中進行查找。不斷重複上述過程。若到達main函數的棧,依舊沒有匹配的,則終止程序。
上述這個沿着調用鏈查找匹配的catch語句的過程稱爲棧展開。找到匹配的catch語句並處理之後,會繼續沿着catch語句後繼繼續執行。
異常捕獲的匹配規則:
異常對象的類型與catch說明符的類型必須徹底匹配。
只有如下幾種狀況例外:
1. 容許從非const對象到const的轉換。
2. 容許從派生類型到基類類型的轉換。
3. 將數組轉換爲指向數組類型的指針,將函數轉換爲指向函數類型的指針。
異常處理總結:
異常處理就是經過throw,try,catch,這三個關鍵字,來發現異常,並拋出異常,捕獲異常,能夠作出相應的處理。(這只是簡單的異常處理)