天天看點

linux c++異常處理,C++中的異常處理

1、C++異常處理

(1)C++内置了異常處理的文法元素,try...catch...,這是兩個新的關鍵字在C++中

@1:try語句代碼塊中用來處理正常代碼邏輯

@2:catch語句代碼塊中用來處理異常情況

@3:try語句中的異常由對應的catch語句進行處理

try

{

douuble r = divide(1, 0);

}

catch(...)

{

cout << "Divide by zero..." << endl;

}

@4:try語句代碼塊中用來處理可能發生異常的正常邏輯代碼,當try代碼塊中的代碼發生了異常,就會抛出異常,catch語句就會捕捉到這個異常,進入到catch語句中進行處理這個異常。

(2)那麼try代碼塊中的語句中是如何抛出異常的呢?

@1:C++通過throw關鍵字抛出異常資訊

如:使用throw語句進行異常抛出

double divide(double a, double b)

{

const double delta = 0.000000000001;

double ret = 0;

if ( !((-delta < b) && (b < delta)) )

{

ret = a / b;

}

else

{

throw 0;//産生除0異常,這裡是0這個字面常量來代碼了目前的異常元素,異常元素可以是字元串,可以是對象,可以是一個值等等

//當程式執行到throw時,就會傳回到調用這個divide函數的調用點,try就會将這個異常元素轉給catch語句,catch語句塊就會抓住這個異常元素

}

return ret;

}

2、C++異常處理分析

(1)throw抛出的異常必須被catch處理

@1:目前函數能夠處理異常,程式繼續往下執行

@2:目前函數如果無法處理收到的異常,則函數停止執行,并傳回

(2)未被處理的異常會順着函數調用棧向上傳播,直到被處理為止,否則程式将停止執行。

比如:如果function1函數調用了function2函數,function2函數調用了function3函數,在function3函數中執行執行,并抛出了異常,也就是throw了,那麼這個異常就會先看function3這個函數有沒有能力處理這個異常(也就是在沒在try中,有沒有對應的catch處理的異常類型),如果有就進行異常處理了,如果沒有function3這個函數就會立即停止執行,并代碼着異常傳回給function2調用function3函數的調用點,如果function2沒有進行處理(沒有在try中,也沒有catch處理的相關類型),function2就會立即停止執行,帶着異常傳回給function1函數調用function2函數的調用點。如果都沒有對throw扔出的這個異常元素進行異常處理的話(函數調用沒在try中也沒有對應的catch異常處理的相關類型),整個程式就會放棄執行

例:throw抛出異常,對異常進行處理,try...catch

#include

#include

using namespace std;

double divide(double a, double b)

{

const double delta = 0.00000000001;

double ret = 0;

if ( !((-delta < b) && (b < delta)) )

{

ret = a / b;

}

else

{

throw 0;//産生除0異常,這裡是0這個int類型的值來代碼了目前的異常元素,異常元素可以是字元串,可以是對象,可以是一個值等等

//當程式執行到throw時,就會傳回到調用這個divide函數的調用點,try就會将這個異常元素轉給catch語句,catch語句塊就會抓住這個異常元素//如果沒有對應的catch對這個異常進行處理,程式将會放棄執行

}

return ret;

}

int main(int argc, char *argv[])

{

double num = 0;

try

{

num = divide(1, 1);//執行到divide函數throw語句時,就會傳回throw語句後面的異常元素給這個try,這個try将異常元素給了catch,catch對這個異常進行處理。

//如果沒有對異常進行處理的操作,但你throw還抛出了異常,程式會停止運作

cout << "num = " << num << endl;

}

catch(...)

{

cout << "Divide by zero ...." << endl;

}

return 0;

}

(3)同一個try語句可以跟上多個catch語句

@1:catch語句可以定義具體處理的異常類型

@2:不同類型的異常由不同的catch語句負責處理

@3:try語句中可以抛出任何類型的異常

@4:catch(...)用于處理所有類型的異常,并且這個catch(...)裡面是3個點的catch語句塊隻能放在最後catch處理的情況,當有其他catch存在時。

@5:任何異常都隻能被捕獲(catch)一次

(4)異常處理的比對原則

try

{

throw 1;

}

catch (Type1 t1)

{

}

catch (Type2 t2)

{

}

catch (TypeN tn)

{

}

catch (...)//這個catch,處理任何類型的異常,當有其他catch存在時,隻能作為最後的catch處理情況

{

}

異常抛出後,至上而下嚴格的比對每一個catch語句處理的類型。異常處理比對時,不進行任何的類型轉換。是以是嚴格比對的。

如果目前抛出異常的函數沒有對這個異常處理,就會沿着目前函數的調用棧,順序的傳回,直到被處理,如果都沒有進行這個異常處理,程式就會停止執行

例:一個try抛出異常,多個catch進行異常類型比對處理異常的情況

#include

#include

using namespace std;

void Demo1()

{

try

{

throw 0;//直接抛出異常,這個是int類型的

}

catch (char c)

{

cout << "catch (char c)" << endl;

}

catch (double d)

{

cout << "catch (double d)" << endl;

}

catch (string s)

{

cout << "catch (string s)" << endl;

}

catch (int i)

{

cout << "catch (int i)" << endl;

}

catch (...)

{

cout << "catch (...)" << endl;

}

}

void Demo2()

{

try

{

throw "haha";//這個const char* 類型的

}

catch (char *s)

{

cout << "catch (char *s)" << endl;

}

catch (string ss)

{

cout << "catch (string ss)" << endl;

}

catch (const char * cs)

{

cout << "catch (const char * cs)" << endl;

}

}

int main(int argc, char *argv[])

{

Demo1();

try

{

Demo2();

}

catch (...)

{

cout << "catch (...)" << endl;

}

return 0;

}

最後的執行結果,會列印catch (int i)和catch (...)

3、catch語句塊中也可以抛出異常

try

{

func();

}

catch(int i)

{

throw i;//将捕獲到的異常重新抛出。

}

catch(...)

{

throw;//将捕獲到的異常重新抛出

}

catch中抛出的異常需要外層的try...catch...捕獲。

(1)C++中之是以支援catch語句塊中抛出異常,是因為我們在工程開發中,會經常的使用第三方庫進行開發,如果第三方庫中的func函數在使用時有可能會抛出異常,并且抛出的異常是-1,-2,-3等int類型異常,每一個異常元素對應的意思可以看第三方庫中的文檔來知道,但是我們在開發中,如果真遇到了第三方庫抛出了異常,但是我們确無法直覺的直接從這幾個-1,-2,-3異常元素來知道每一個異常元素對應的是什麼情況,隻能去查第三方庫提供的文檔來知道,這是很浪費時間的,是以我們為了開發效率,是以我們将會将第三方庫抛出的異常,進行統一的封裝,也就是将func函數在我們自己寫的Myfunc函數中調用,在Myfunc函數中,我們将第三方庫func函數中可能抛出的異常元素進行重解釋在抛出,這樣我們就可以在工程開發中直接處理Myfunc這個函數抛出的重解釋了第三方庫func函數中抛出的異常。友善處理。

例:工程中在catch中抛出異常的用法,用于将第三方庫中提供的函數抛出的異常進行重解釋。

#include

#include

using namespace std;

void func(int i)

{

if (i < 10)

{

throw -1;

}

else if (i == 11)

{

throw -2;

}

else if (i > 100)

{

throw -3;

}

}

void MyFunc(int i)//自己提供的函數,完成和func一樣的功能,隻是為了重解釋一下第三方庫func函數抛出的異常

{

try

{

func(i);

}

catch (int i)

{

switch (i)//對第三方func函數抛出的異常進行重解釋。

{

case -1:

throw "Invalid Exception";

break;

case -2:

throw "RunException";

break;

case -3:

throw "Timeout Exceptin";

break;

}

}

}

int main(void)

{

try

{

MyFunc(101);

}

catch (const char *cs)

{

cout << "Exception Info: " << cs << endl;

}

return 0;

}

4、異常的類型可以是自定義的類類型

(1)對于類類型的比對依然是至上而下的嚴格比對

(2)指派相容性原則在異常比對中依然适用(子類的異常對象,可以被父類的catch語句塊抓住)

(3)是以一般而言:

@1:比對子類異常的catch放在上部

@2:比對父類異常的catch放在下部

(5)在工程中會定義一系列的異常類

@1:每個類代表工程中可能出現的一種異常類型

@2:代碼複用時可能需要重解釋不同的異常類

@3:在定義catch語句塊時如果使用的異常是類對象,那麼推薦使用引用作為參數,因為這樣可以避開拷貝構造,提高程式效率

例:用異常類對異常進行重解釋

#include

#include

using namespace std;

class Base

{

};

class Exception: public Base//繼承了Base,是以catch接受這個類抛出的異常時,catch接受這個父類的異常處理要放到後面

{

private:

int m_id;//異常的ID号,也就是第三方庫func函數中抛出異常的異常元素号。

string m_desc;//異常的資訊描述

public:

Exception(int id, string desc)

{

m_id = id;

m_desc = desc;

}

int id() const

{

return m_id;

}

string description() const

{

return m_desc;

}

};

void func(int i)

{

if (i < 10)

{

throw -1;

}

else if (i == 11)

{

throw -2;

}

else if (i > 100)

{

throw -3;

}

}

void MyFunc(int i)//自己提供的函數,完成和func一樣的功能,隻是為了重解釋一下第三方庫func函數抛出的異常

{

try

{

func(i);

}

catch (int i)

{

switch (i)//對第三方func函數抛出的異常進行重解釋。

{

case -1:

throw Exception(-1, "Invalid Exception");

break;

case -2:

throw Exception(-2, "Run Exception");

break;

case -3:

throw Exception(-3, "Timeout Exceptin");

break;

}

}

}

int main(void)

{

try

{

MyFunc(111);

}

catch (const Exception& e)

{

cout << "Exception Info: " << endl;

cout << "ID: " << e.id() << endl;

cout << "Description: " << e.description() << endl;

}

catch (const Base& e)//父類的接受異常要放到後面,因為指派相容性原則,如果這個接受異常放在了前面,那麼抛出的異常就會被父類接受到了

{

cout << "catch (const Base& e)" << endl;

}

return 0;

}

6、C++标準庫中提供了實用異常類族,使用時要包含這個頭檔案,并且要聲明使用的命名空間是std

(1)标準庫中的異常都是從exception頂層父類派生的

(2)exception類有兩個主要分支,在于異常的類型是不一樣的

@1:logic_error

常用于程式中的可避免邏輯錯誤,(out_of_range("可以有參數,字元串參數,隻是哪個函數發生的異常");數組通路越界,參數錯誤等)

@2:runtime_error

常用于程式中無法避免的惡性錯誤()