C++拋出和接收異常的順序
異常(exception)是C++語(yǔ)言引入的錯(cuò)誤處理機(jī)制。它 采用了統(tǒng)一的方式對(duì)程序的運(yùn)行時(shí)錯(cuò)誤進(jìn)行處理,具有標(biāo)準(zhǔn)化、安全和高效的特點(diǎn)。C++為了實(shí)現(xiàn)異常處理,引入了三個(gè)關(guān)鍵字:try、throw、catch。異常由throw拋出,格式為throw[expression],由catch捕捉。Try語(yǔ)句塊是可能拋出異常的語(yǔ)句塊,它通常和一個(gè)或多個(gè)catch語(yǔ)句塊連續(xù)出現(xiàn)。
try語(yǔ)句塊和catch語(yǔ)句塊必須相互配合,以下三種情況都會(huì)導(dǎo)致編譯錯(cuò)誤:
(1)只有try語(yǔ)句塊而沒(méi)有catch語(yǔ)句塊,或者只有catch語(yǔ)句塊而沒(méi)有try語(yǔ)句塊;
(2)在try語(yǔ)句塊和catch語(yǔ)句塊之間夾雜有其他語(yǔ)句;
(3)當(dāng)try語(yǔ)句塊后跟有多個(gè)catch語(yǔ)句塊時(shí),catch語(yǔ)句塊之間夾雜有其他語(yǔ)句;
(4)同一種數(shù)據(jù)類型的傳值catch分支與傳引用catch分支不能同時(shí)出現(xiàn)。
在拋出和接收異常的過(guò)程中,我們還要注意以下幾點(diǎn)。
1.被拋出的異常對(duì)象什么時(shí)候被銷毀?
用throw語(yǔ)句拋出一個(gè)對(duì)象時(shí),會(huì)構(gòu)造一個(gè)新的對(duì)象,這個(gè)對(duì)象就是異常對(duì)象。該對(duì)象的生命周期從被拋出開(kāi)始計(jì)算,一直到被某個(gè)catch語(yǔ)句捕捉,就會(huì)在該catch語(yǔ)句塊執(zhí)行完畢后被銷毀??疾烊缦鲁绦?。
#include <iostream> using namespace std; class ExClass { int num; public: ExClass(int i) { cout<<"Constructing exception object with num="<<i<<endl; num=i; } ExClass(ExClass& e) { cout<<"Copy Constructing exception object with num="<<e.num+1<<endl; num=e.num+1; } ~ExClass() { cout<<"Destructing exception object with num="<<num<<endl; } void show() { cout<<"the number is "<<num<<endl; } }; int main() { ExClass obj(99); try { throw obj; //導(dǎo)致輸出:Constructing exception object with num=100 } catch(double f) { cout<<"exception catched"<<endl; } //導(dǎo)致輸出:Constructing exception object with num=101 catch(ExClass e) { e.show(); } cout<<"after catch"<<endl; }
程序輸出結(jié)果是:
Constructing exception object with num=99
Copy Constructing exception object with num=100
Copy Constructing exception object with num=101
the number is 101
Destructing exception object with num=101
Destructing exception object with num=100
after catch
Destructing exception object with num=99
用throw語(yǔ)句拋出一個(gè)對(duì)象時(shí),會(huì)構(gòu)造一個(gè)新的對(duì)象,這個(gè)對(duì)象就是異常對(duì)象。該對(duì)象的生命周期從被拋出時(shí)開(kāi)始計(jì)算,一直到被某個(gè)catch語(yǔ)句捕獲,就會(huì)在該catch語(yǔ)句塊執(zhí)行完畢后被銷毀。在上面的程序中,異常對(duì)象的num值為100,“Destructing exception object with num=100”這句話在“after catch”之前輸出,正好說(shuō)明異常對(duì)象的銷毀時(shí)間是在它被捕獲的catch塊執(zhí)行之后。
所以的catch分支在執(zhí)行時(shí)類似一次函數(shù)調(diào)用,catch 的參數(shù)相當(dāng)于函數(shù)的形參,而被拋出的異常對(duì)象相當(dāng)于函數(shù)調(diào)用時(shí)的實(shí)參。當(dāng)形參與實(shí)參成功匹配時(shí),就說(shuō)明異常被某個(gè)catch分支所捕獲。catch后面的參數(shù)只能采用傳值、傳引用和傳指針三種方式,如果采用傳值方式,則會(huì)生成實(shí)參的一個(gè)副本,如果實(shí)參是一個(gè)對(duì)象,就會(huì)導(dǎo)致構(gòu)造函數(shù)被調(diào)用。在上面的程序中,執(zhí)行catch(ExClass e) 語(yǔ)句就是利用異常對(duì)象構(gòu)造一個(gè)對(duì)象e,因此會(huì)調(diào)用拷貝構(gòu)造函數(shù)。
要注意的是:同一種數(shù)據(jù)類型的傳值catch分支和傳引用catch分支不能同時(shí)出現(xiàn)。
2.異常如果在當(dāng)前函數(shù)沒(méi)有被捕獲會(huì)發(fā)生什么?
在某些情況下,可能所有的catch分支都無(wú)法捕獲到拋出的異常,這將導(dǎo)致當(dāng)前函數(shù)執(zhí)行的結(jié)束,并返回到主調(diào)函數(shù)中。在主調(diào)函數(shù)中,將繼續(xù)以上的捕捉異常的過(guò)程,直到異常被捕捉或最終結(jié)束整個(gè)程序??疾烊缦鲁绦?。
#include <iostream> using namespace std; class ExClass { int num; public: ExClass(int i) { cout<<"Constructing exception object with num="<<i<<endl; num=i; } ExClass(ExClass& e) { cout<<"Copy Constructing exception object with num="<<e.num+1<<endl; num=e.num+1; } ~ExClass() { cout<<"Destructing exception object with num="<<num<<endl; } void show() { cout<<"the number is "<<num<<endl; } }; void throwExFunc() { try{ throw ExClass(199); } catch(double f){ cout<<"double exception catched"<<endl; } cout<<"exit throwExFunc()"<<endl; } int main() { try { throwExFunc(); } catch(ExClass e) { e.show(); } catch(...) { cout<<"all will fall in"<<endl; } cout<<"continue to execute"<<endl; }
程序的輸出結(jié)果:
Constructing exception object with num=199
Copy Constructing exception object with num=200
the number is 200
Destructing exception object with num=200
Destructing exception object with num=199
continue to execute
從程序的結(jié)果可以看出:
(1)被拋出的異常對(duì)象的num值為199,由于它沒(méi)有在函數(shù)throwExFunc()中被捕捉,所以它導(dǎo)致了throwExFunc()的執(zhí)行結(jié)束(否則會(huì)輸出:exit throwExFunc())。在main()函數(shù)中,catch(ExClass e)捕獲了異常對(duì)象,通過(guò)復(fù)制構(gòu)造函數(shù)產(chǎn)生對(duì)象e,e的num值為200,catch語(yǔ)句塊運(yùn)行完結(jié)束后,對(duì)象e首先被銷毀,緊接著銷毀異常對(duì)象。在這之后,程序繼續(xù)運(yùn)行,輸出:continue to execute。
(2)catch(…)的意思是可以捕獲所有類型的異常。不提倡隨意地使用catch(…),因?yàn)檫@會(huì)導(dǎo)致異常類型的不精確處理,并降低程序的運(yùn)行效率。但是,在程序的開(kāi)發(fā)階段,catch(…)還是有用的,因?yàn)槿绻诰陌才女惓2东@之后,還是進(jìn)入了catch(…)語(yǔ)句塊,說(shuō)明前面的代碼存在缺陷,需要進(jìn)一步改正。
(3)在捕捉異常對(duì)象時(shí),還可以采用傳引用的方式,例如把catch語(yǔ)句寫(xiě)成catch(ExClass& e),這樣就可以不必產(chǎn)生異常對(duì)象的副本,減少程序的運(yùn)行開(kāi)銷,提高運(yùn)行效率。
(4)在拋出異常時(shí),還可以拋出一個(gè)指針。當(dāng)然這種做法并不總是安全的。如果要確保安全,應(yīng)該將指針指向全局(靜態(tài))對(duì)象的指針或指向動(dòng)態(tài)申請(qǐng)的空間,或者被拋出的指針在本函數(shù)內(nèi)被捕獲。否則,利用一個(gè)被拋出的指向已經(jīng)被銷毀的對(duì)象指針很危險(xiǎn)。如果實(shí)在要用,首先,必須保證對(duì)象的析構(gòu)函數(shù)不能對(duì)對(duì)象的內(nèi)容作損傷性的修改,其次,對(duì)象的空間沒(méi)有被其他新產(chǎn)生的變量覆蓋。也就說(shuō),盡管對(duì)象被釋放,但它的有效內(nèi)容依然保留在棧中。
以上就是C++拋出和接收異常的順序的詳細(xì)內(nèi)容,更多關(guān)于C++拋出和接收異常的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
c++實(shí)現(xiàn)合并文件以及拆分實(shí)例代碼
這篇文章主要介紹了c++實(shí)現(xiàn)合并文件以及拆分實(shí)例代碼,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01Qt顯示QImage圖像在label上,并保持自適應(yīng)大小問(wèn)題
這篇文章主要介紹了Qt顯示QImage圖像在label上,并保持自適應(yīng)大小問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11淺談C語(yǔ)言中的強(qiáng)符號(hào)、弱符號(hào)、強(qiáng)引用和弱引用
這篇文章主要介紹了C語(yǔ)言中的強(qiáng)符號(hào)、弱符號(hào)、強(qiáng)引用和弱引用的定義及相關(guān)內(nèi)容,非常的簡(jiǎn)單易懂,有需要的朋友可以參考下2014-10-10C++棧實(shí)現(xiàn)逆波蘭式的應(yīng)用
逆波蘭式指的是操作符在其所控制的操作數(shù)后面的表達(dá)式。本文主要介紹了C++棧實(shí)現(xiàn)逆波蘭式的應(yīng)用,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11二叉樹(shù)遍歷 非遞歸 C++實(shí)現(xiàn)代碼
對(duì)于二叉樹(shù),有前序、中序以及后序三種遍歷方法。因?yàn)闃?shù)的定義本身就是遞歸定義,因此采用遞歸的方法去實(shí)現(xiàn)樹(shù)的三種遍歷不僅容易理解而且代碼很簡(jiǎn)潔。而對(duì)于樹(shù)的遍歷若采用非遞歸的方法,就要采用棧去模擬實(shí)現(xiàn)2013-09-09