“拋出一個(gè)Exception”與“傳遞一個(gè)參數(shù)”的區(qū)別
“拋出一個(gè)Exception”與“傳遞一個(gè)參數(shù)”的區(qū)別
兩個(gè)類比的概念,下面的“==”表示類比的意思:
調(diào)用端==拋出端
被調(diào)端==捕獲端
1。調(diào)用函數(shù),控制權(quán)最終會(huì)回到調(diào)用端;但拋出異常后,控制權(quán)就不會(huì)再回到拋出端了;
2。一個(gè)對(duì)象拋出時(shí)總是要發(fā)生拷貝(即扔出一個(gè)副本),而一個(gè)參數(shù)被傳遞時(shí)卻不會(huì)發(fā)生拷貝(即扔出對(duì)象本身)。注意,這里只談道拋出和傳遞,而未涉及到接受和捕獲。
throw obj;//總會(huì)調(diào)用obj的copy constructor,如果obj為對(duì)象。
****:這里必須要提及的一點(diǎn)是“拷貝動(dòng)作永遠(yuǎn)都是以對(duì)象的靜態(tài)型別為本的”,這是C++的一條通用的適用原則。
3。throw;//這個(gè)句子有點(diǎn)特殊,它是將捕獲到的異常拋出去,因此它必須位于catch塊內(nèi)才可以使用。此外,這種拋出并不會(huì)復(fù)制對(duì)象(因?yàn)樗鼪]有拋出對(duì)象諸如throw obj;而是拋出異常,因此捕獲到啥就拋出啥),因此雖然第二條法則是真理,但是大家也千萬不要妄自揣測——catch到的都是副本,因?yàn)檫@里就告訴了你有可能不是的,因?yàn)閠hrow;這種特殊情況的存在。
4。catch(A a);和catch(A& a);還有catch(const A& a);三種方式都可以捕捉到類型為A的異常對(duì)象,第一種方式和第二種方式的區(qū)別在于接受異常對(duì)象時(shí)是否需要付出再拷貝一次的代價(jià),即第一種方式需要把扔出來的對(duì)象再拷貝一次給對(duì)象a;第二種和第三種方式基本差不多,都是引用類型,只不過第三種方式中不能夠修改a的內(nèi)容罷了。現(xiàn)在知道了吧,throw a;catch(A a);這兩句話會(huì)造成調(diào)用兩次A的拷貝構(gòu)造函數(shù)。
此外,大家應(yīng)該知道C++在函數(shù)調(diào)用過程中的一個(gè)準(zhǔn)則是:傳遞臨時(shí)對(duì)象時(shí),接受對(duì)象的形參不能是引用類型,除非是const引用類型。而在catch端就沒有這種限制了,對(duì)于拋出來的臨時(shí)對(duì)象,catch在接收它們時(shí)能夠以引用的方式來接收。
5。從實(shí)參到形參,中間可以進(jìn)行的對(duì)象類型轉(zhuǎn)換有很多種,編譯器可以隱士的為你做這些事情,但是從拋出的對(duì)象到catch端捕獲的對(duì)象中間經(jīng)歷的對(duì)象轉(zhuǎn)換卻只有兩種了:即在繼承體系中的向上塑型和具體型別的指針到void*指針的轉(zhuǎn)換。
6。其實(shí)也可以捕獲指針類別的異常,與捕獲其他對(duì)象沒有區(qū)別,但是如果拋出指針對(duì)象,那么雖然也會(huì)進(jìn)行拷貝,但此時(shí)拷貝的僅僅是指針而已,而不是指針?biāo)赶虻膶?duì)象。但是需要注意的是,這需要注意的是,不要讓該指針指向一個(gè)被定義在try塊內(nèi)的臨時(shí)變量,因?yàn)橐坏┺D(zhuǎn)移到catch塊時(shí),try塊內(nèi)的對(duì)象都會(huì)被銷毀,此時(shí)catch塊內(nèi)的指針實(shí)則指向一個(gè)不存在的對(duì)象。下面這段代碼會(huì)為你演繹拋出指針的情況:
A a;
try{
a.m_nA=999;
throw &a;
}catch(A* pa){
cout<<pa->m_nA<<endl;
pa->m_nA=888;
try{
throw pa;
}
catch(A* pa){
cout<<pa->m_nA<<endl;
}
}
posted on 2008-08-18 16:15 so true 閱讀(341) 評(píng)論(0) 編輯 收藏 所屬分類: C&C++