C++ 異常處理 catch(...)介紹
如果要想使一個(gè)catch block能抓獲多種數(shù)據(jù)類(lèi)型的異常對(duì)象的話,怎么辦?C++標(biāo)準(zhǔn)中定義了一種特殊的catch用法,那就是” catch(…)”。
感性認(rèn)識(shí)
1、catch(…)到底是一個(gè)什么樣的東東,先來(lái)個(gè)感性認(rèn)識(shí)吧!
看例子先:
int main()
{
try
{
cout << "在 try block 中, 準(zhǔn)備拋出一個(gè)異常." << endl;
//這里拋出一個(gè)異常(其中異常對(duì)象的數(shù)據(jù)類(lèi)型是int,值為1)
throw 1;
}
//catch( int& value )
//注意這里catch語(yǔ)句
catch( …)
{
cout << "在 catch(…) block 中, 拋出的int類(lèi)型的異常對(duì)象被處理" << endl;
}
}
2、哈哈!int類(lèi)型的異常被catch(…)抓獲了,再來(lái)另一個(gè)例子:
int main()
{
try
{
cout << "在 try block 中, 準(zhǔn)備拋出一個(gè)異常." << endl;
//這里拋出一個(gè)異常(其中異常對(duì)象的數(shù)據(jù)類(lèi)型是double,值為0.5)
throw 0.5;
}
//catch( double& value )
//注意這里catch語(yǔ)句
catch( …)
{
cout << "在 catch(…) block 中, double類(lèi)型的異常對(duì)象也被處理" << endl;
}
}
3、同樣,double類(lèi)型的異常對(duì)象也被catch(…)塊抓獲了。是的,catch(..)能匹配成功所有的數(shù)據(jù)類(lèi)型的異常對(duì)象,包括C++語(yǔ)言提 供所有的原生數(shù)據(jù)類(lèi)型的異常對(duì)象,如int、double,還有char*、int*這樣的指針類(lèi)型,另外還有數(shù)組類(lèi)型的異常對(duì)象。同時(shí)也包括所有自定義 的抽象數(shù)據(jù)類(lèi)型。例程如下:
int main()
{
try
{
cout << "在 try block 中, 準(zhǔn)備拋出一個(gè)異常." << endl;
//這里拋出一個(gè)異常(其中異常對(duì)象的數(shù)據(jù)類(lèi)型是char*)
char* p=0;
throw p;
}
//catch( char* value )
//注意這里catch語(yǔ)句
catch( …)
{
cout << "在 catch(…) block 中, char*類(lèi)型的異常對(duì)象也被處理" << endl;
}
}
int main()
{
try
{
cout << "在 try block 中, 準(zhǔn)備拋出一個(gè)異常." << endl;
//這里拋出一個(gè)異常(其中異常對(duì)象的數(shù)據(jù)類(lèi)型是int[])
int a[4];
throw a;
}
//catch( int value[] )
//注意這里catch語(yǔ)句
catch( …)
{
cout << "在 catch(…) block 中, int[]類(lèi)型的異常對(duì)象也被處理" << endl;
}
}
4、對(duì)于抽象數(shù)據(jù)類(lèi)型的異常對(duì)象。catch(…)同樣有效,例程如下:
class MyException
{
public:
protected:
int code;
};
int main()
{
try
{
cout << "在 try block 中, 準(zhǔn)備拋出一個(gè)異常." << endl;
//這里拋出一個(gè)異常(其中異常對(duì)象的數(shù)據(jù)類(lèi)型是MyException)
throw MyException();
}
//catch(MyException& value )
//注意這里catch語(yǔ)句
catch( …)
{
cout << "在catch(…) block中, MyException類(lèi)型的異常對(duì)象被處理" << endl;
}
}
對(duì)catch(…)有點(diǎn)迷糊?
1、究竟對(duì)catch(…)有什么迷糊呢?還是看例子先吧!
void main()
{
int* p = 0;
try
{
// 注意:下面這條語(yǔ)句雖然不是throw語(yǔ)句,但它在執(zhí)行時(shí)會(huì)導(dǎo)致系統(tǒng)
// 出現(xiàn)一個(gè)存儲(chǔ)保護(hù)錯(cuò)誤的異常(access violation exception)
*p = 13; // causes an access violation exception;
}
catch(...)
{
//catch(…)能抓獲住上面的access violation exception異常嗎?
cout << "在catch(…) block中" << endl;
}
}
請(qǐng)問(wèn)上面的程序運(yùn)行時(shí)會(huì)出現(xiàn)什么結(jié)果嗎?catch(…)能抓獲住系統(tǒng)中出現(xiàn)的access violation exception異常嗎?朋友們!和我們的主人公阿愚一樣,自己動(dòng)手去測(cè)試一把!
結(jié)果又如何呢?實(shí)際上它有兩種不同的運(yùn)行結(jié)果,在window2000系統(tǒng)下用VC來(lái)測(cè)試運(yùn)行這個(gè)小程序時(shí),發(fā)現(xiàn)程序能輸出"在catch(…) block中"的語(yǔ)句在屏幕上,也即catch(…) 能成功抓獲住系統(tǒng)中出現(xiàn)的access violation exception異常,很厲害吧!但如果這個(gè)同樣的程序在linux下用gcc編譯后運(yùn)行時(shí),程序?qū)?huì)出現(xiàn)崩潰,并在屏幕上輸出”segment fault”的錯(cuò)誤信息。
主人公阿愚有點(diǎn)急了,也開(kāi)始有點(diǎn)迷糊了,為什么?為什么?為什么同樣一個(gè)程序在兩種不同的系統(tǒng)上有不同的表現(xiàn)呢?其原因就是:對(duì)于這種由于硬件或操作 系統(tǒng)出現(xiàn)的系統(tǒng)異常(例如說(shuō)被零除、內(nèi)存存儲(chǔ)控制異常、頁(yè)錯(cuò)誤等等)時(shí),window2000系統(tǒng)有一個(gè)叫做結(jié)構(gòu)化異常處理(Structured Exception Handling,SEH)的機(jī)制,這個(gè)東東太厲害了,它能和VC中的C++異常處理模型很好的結(jié)合上(實(shí)際上VC實(shí)現(xiàn)的C++異常處理模型很大程度上建 立在SEH機(jī)制之上的,或者說(shuō)它是SEH的擴(kuò)展,后面文章中會(huì)詳細(xì)闡述并分析這個(gè)久富盛名的SEH,看看catch(…)是如何神奇接管住這種系統(tǒng)異常出 現(xiàn)后的程序控制流的,不過(guò)這都是后話)。而在linux系統(tǒng)下,系統(tǒng)異常是由信號(hào)處理編程方法來(lái)控制的(信號(hào)處理編程,signal processing progamming。在介紹unix和linux下如何編程的書(shū)籍中,都會(huì)有對(duì)信號(hào)處理編程詳細(xì)的介紹,當(dāng)然執(zhí)著的主人公阿愚肯定對(duì)它也不會(huì)放過(guò),會(huì)深 入到unix沿襲下來(lái)的信號(hào)處理編程內(nèi)部的實(shí)現(xiàn)機(jī)制,并嘗試完善改進(jìn)它,使它也能夠較好地和C++異常處理模型結(jié)合上)。
那么C++標(biāo)準(zhǔn)中對(duì)于這種同一個(gè)程序有不同的運(yùn)行結(jié)果有何解釋呢?這里需要注意的是,window2000系統(tǒng)下catch(…)能捕獲住系統(tǒng)異常, 這完全是它自己的擴(kuò)展。在C++標(biāo)準(zhǔn)中并沒(méi)有要求到這一點(diǎn),它只規(guī)定catch(…)必須能捕獲程序中所有通過(guò)throw語(yǔ)句拋出的異常。因此上面的這個(gè) 程序在linux系統(tǒng)下的運(yùn)行結(jié)果也完全是符合C++標(biāo)準(zhǔn)的。雖然大家也必須承認(rèn)window2000系統(tǒng)下對(duì)C++異常處理模型的這種擴(kuò)展確實(shí)是一個(gè)很 不錯(cuò)的完善,極大得提高了程序的安全性。
為什么要用catch(…)這個(gè)東東?
程序員朋友們也許會(huì)說(shuō),這還有問(wèn)嗎?這篇文章的一開(kāi)始不就講到了嗎?catch(…)能夠捕獲多種數(shù)據(jù)類(lèi)型的異常對(duì)象,所以它提供給程序員一種對(duì)異常 對(duì)象更好的控制手段,使開(kāi)發(fā)的軟件系統(tǒng)有很好的可靠性。因此一個(gè)比較有經(jīng)驗(yàn)的程序員通常會(huì)這樣組織編寫(xiě)它的代碼模塊,如下:
void Func()
{
try
{
// 這里的程序代碼完成真正復(fù)雜的計(jì)算工作,這些代碼在執(zhí)行過(guò)程中
// 有可能拋出DataType1、DataType2和DataType3類(lèi)型的異常對(duì)象。
}
catch(DataType1& d1)
{
}
catch(DataType2& d2)
{
}
catch(DataType3& d3)
{
}
// 注意上面try block中可能拋出的DataType1、DataType2和DataType3三
// 種類(lèi)型的異常對(duì)象在前面都已經(jīng)有對(duì)應(yīng)的catch block來(lái)處理。但為什么
// 還要在最后再定義一個(gè)catch(…) block呢?這就是為了有更好的安全性和
// 可靠性,避免上面的try block拋出了其它未考慮到的異常對(duì)象時(shí)導(dǎo)致的程
// 序出現(xiàn)意外崩潰的嚴(yán)重后果,而且這在用VC開(kāi)發(fā)的系統(tǒng)上更特別有效,因
// 為catch(…)能捕獲系統(tǒng)出現(xiàn)的異常,而系統(tǒng)異常往往令程序員頭痛了,現(xiàn)
// 在系統(tǒng)一般都比較復(fù)雜,而且由很多人共同開(kāi)發(fā),一不小心就會(huì)導(dǎo)致一個(gè)
// 指針變量指向了其它非法區(qū)域,結(jié)果意外災(zāi)難不幸發(fā)生了。catch(…)為這種
// 潛在的隱患提供了一種有效的補(bǔ)救措施。
catch(…)
{
}
}
還有,特別是VC程序員為了使開(kāi)發(fā)的系統(tǒng)有更好的可靠性,往往在應(yīng)用程序的入口函數(shù)中(如MFC框架的開(kāi)發(fā)環(huán)境下 CXXXApp::InitInstance())和工作線程的入口函數(shù)中加上一個(gè)頂層的trycatch塊,并且使用catch(…)來(lái)捕獲一切所有的 異常,如下:
BOOL CXXXApp::InitInstance()
{
if (!AfxSocketInit())
{
AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
return FALSE;
}
AfxEnableControlContainer();
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.
#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif
// 注意這里有一個(gè)頂層的trycatch塊,并且使用catch(…)來(lái)捕獲一切所有的異常
try
{
CXXXDlg dlg;
m_pMainWnd = &dlg;
int nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
// TODO: Place code here to handle when the dialog is
// dismissed with OK
}
else if (nResponse == IDCANCEL)
{
// TODO: Place code here to handle when the dialog is
// dismissed with Cancel
}
}
catch(…)
{
// dump出系統(tǒng)的一些重要信息,并通知管理員查找出現(xiàn)意外異常的原因。
// 同時(shí)想辦法恢復(fù)系統(tǒng),例如說(shuō)重新啟動(dòng)應(yīng)用程序等
}
// Since the dialog has been closed, return FALSE so that we exit the
// application, rather than start the application's message pump.
return FALSE;
}
通過(guò)上面的例程和分析可以得出,由于catch(…)能夠捕獲所有數(shù)據(jù)類(lèi)型的異常對(duì)象,所以在恰當(dāng)?shù)牡胤绞褂胏atch(…)確實(shí)可以使軟件系統(tǒng)有著更 好的可靠性。這確實(shí)是大家使用catch(…)這個(gè)東東最好的理由。但不要誤會(huì)的是,在C++異常處理模型中,不只有catch(…)方法能夠捕獲幾乎所 有類(lèi)型的異常對(duì)象.
您可能感興趣的文章
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 01-10深入理解C++中常見(jiàn)的關(guān)鍵字含義
- 01-10使用C++實(shí)現(xiàn)全排列算法的方法詳解
- 01-10c++中inline的用法分析
- 01-10用C++實(shí)現(xiàn)DBSCAN聚類(lèi)算法
- 01-10全排列算法的非遞歸實(shí)現(xiàn)與遞歸實(shí)現(xiàn)的方法(C++)
- 01-10C++大數(shù)模板(推薦)
- 01-10淺談C/C++中的static與extern關(guān)鍵字的使用詳解
- 01-10深入C/C++浮點(diǎn)數(shù)在內(nèi)存中的存儲(chǔ)方式詳解
- 01-10異步http listener 完全并發(fā)處理懲罰http懇求的小例子


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹(shù)的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 04-02c語(yǔ)言函數(shù)調(diào)用后清空內(nèi)存 c語(yǔ)言調(diào)用
- 04-02func函數(shù)+在C語(yǔ)言 func函數(shù)在c語(yǔ)言中
- 04-02c語(yǔ)言的正則匹配函數(shù) c語(yǔ)言正則表達(dá)
- 04-02c語(yǔ)言用函數(shù)寫(xiě)分段 用c語(yǔ)言表示分段
- 04-02c語(yǔ)言中對(duì)數(shù)函數(shù)的表達(dá)式 c語(yǔ)言中對(duì)
- 04-02c語(yǔ)言編寫(xiě)函數(shù)冒泡排序 c語(yǔ)言冒泡排
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 04-02c語(yǔ)言分段函數(shù)怎么求 用c語(yǔ)言求分段
- 04-02C語(yǔ)言中怎么打出三角函數(shù) c語(yǔ)言中怎
- 04-02c語(yǔ)言調(diào)用函數(shù)求fibo C語(yǔ)言調(diào)用函數(shù)求
隨機(jī)閱讀
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
- 01-10C#中split用法實(shí)例總結(jié)
- 01-11Mac OSX 打開(kāi)原生自帶讀寫(xiě)NTFS功能(圖文
- 01-10SublimeText編譯C開(kāi)發(fā)環(huán)境設(shè)置
- 04-02jquery與jsp,用jquery
- 01-10delphi制作wav文件的方法
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改


