C++異常處理的方式總結(jié)
個(gè)詞,今天就來做詳細(xì)的介紹,文中通過代碼示例給大家介紹的非常詳細(xì),具有一定參考價(jià)值,需要的朋友可以參考下
1. 前言
C++有一套獨(dú)立的異常處理機(jī)制,相信大家一定聽說過try,catch這兩個(gè)詞,今天就來做詳細(xì)的介紹
本篇文章著重講解C++異常處理的方式,三個(gè)關(guān)鍵字,tyr,catch,throw,并且介紹異常的用法和自定義體系的異常以及智能指針在異常處理中的使用場景.其中,會(huì)復(fù)習(xí)C語言異常處理的方式
2. C語言處理異常的方式
最經(jīng)典的處理方式:使用assert
assert的缺陷:
如果在代碼中使用assert,則只在debug模式下有效,在release模式下會(huì)失效.并且只要有錯(cuò)誤就會(huì)直接終止程序,這明顯不符合實(shí)際,比如說在使用微信時(shí),由于網(wǎng)絡(luò)問題信息沒發(fā)出去,這時(shí)直接將微信程序終止了,這樣做會(huì)被亂棍打死!
C語言還能用錯(cuò)誤碼返回異常信息
錯(cuò)誤碼errno的缺陷:
返回的錯(cuò)誤碼是一個(gè)數(shù)字,程序員還需去查表來得知這個(gè)錯(cuò)誤碼是什么意思,并且就算查找了錯(cuò)誤碼的信息,可能它說的不清楚,也不好看錯(cuò)誤信息
綜上所述,C語言處理異常的方式還是不夠完美,于是祖師爺寫了一套自己的
3. C++異常概念
當(dāng)一個(gè)函數(shù)發(fā)現(xiàn)自己無法處理的錯(cuò)誤時(shí)就可以拋出異常,讓函數(shù)的直接或間接的調(diào)用者處理這個(gè)錯(cuò)誤。
throw: 當(dāng)問題出現(xiàn)時(shí),程序會(huì)拋出一個(gè)異常。這是通過使用 throw 關(guān)鍵字來完成的catch: 在您想要處理問題的地方,通過異常處理程序捕獲異常.catch 關(guān)鍵字用于捕獲異常try: try 塊中的代碼標(biāo)識(shí)將被激活的特定異常,它后面通常跟著一個(gè)或多個(gè) catch 塊。
使用方法:
try{
int a,b;
cin>>a>>b;
if(b == 0)
throw "除0錯(cuò)誤"
cout<<(a/b)<<endl;
}
catch(string str)
{
//......
}
如果有一個(gè)塊拋出一個(gè)異常,捕獲異常的方法會(huì)使用 try 和 catch 關(guān)鍵字。try 塊中放置可能拋出異常的代碼,try 塊中的代碼被稱為保護(hù)代碼,一旦throw后,會(huì)直接跳到catch的位置,后面的代碼不會(huì)執(zhí)行
4. 異常的拋出和匹配原則
異常的拋出和匹配有以下機(jī)制:
拋出的內(nèi)容和捕捉的內(nèi)容要一致
如果你在throw時(shí)拋出一個(gè)字符串,但是在catch捕獲異常時(shí)的參數(shù)卻寫的是整數(shù)那么這個(gè)拋出的異常就不會(huì)去這個(gè)catch
void a(){throw "測試中";}
void b(){a()}
void c(){b()}
int main()
{
try{
c();
}
catch(string str)
{}
try可以嵌套多層
try和catch不僅僅可以在一個(gè)作用域使用,還可以在最外層try,然后嵌套多層函數(shù),在最里面的函數(shù)throw!
void a(){throw "測試中";}
void b(){a()}
void c(){b()}
int main()
{
try{
c();
}
catch(string str)
{}
throw和catch遵循就近原則
若寫了多個(gè)catch,并且這些catch都和throw的內(nèi)容匹配,則會(huì)跳轉(zhuǎn)到與throw最近的內(nèi)個(gè)catch中!
double Division(int a, int b)
{
// 當(dāng)b == 0時(shí)拋出異常
if (b == 0)
throw "除0錯(cuò)誤!";
else
return ((double)a / (double)b);
}
void Func()
{
int len, time;
cin >> len >> time;
cout << Division(len, time) << endl;
catch (const char* errmsg) {//這個(gè)catch與throw相距最近,會(huì)優(yōu)先到這兒
cout << errmsg << "111" << endl;
}
}
int main()
{
try {
Func();
}
catch (const char* errmsg) {
cout << errmsg << "222" << endl;
}
return 0;
}
catch(...)可以捕獲任意類型的異常
在公司寫大工程的時(shí)候,會(huì)和很多同事合作寫代碼,大家都會(huì)拋出異常,但是你不能確定是不是所有人拋出的類型你都有相應(yīng)的catch可以接收,若拋出一個(gè)異常沒有被捕獲會(huì)直接報(bào)錯(cuò),所以…的作用很明顯,用來兜底!一般用于接收一些未知異常
double Division(int a, int b)
{
// 當(dāng)b == 0時(shí)拋出異常
if (b == 0)
throw "除0錯(cuò)誤!";
else
return ((double)a / (double)b);
}
void Func()
{
int len, time;
cin >> len >> time;
cout << Division(len, time) << endl;
catch (const char* errmsg) {//這個(gè)catch與throw相距最近,會(huì)優(yōu)先到這兒
cout << errmsg << "111" << endl;
}
}
int main()
{
try {
Func();
}
catch (const char* errmsg) {
cout << errmsg << "222" << endl;
}
catch(...){
cout<<"未知異常"<<endl;
}
return 0;
}
基類可以接受拋出的子類對(duì)象
拋出和捕獲有一個(gè)例外,那就是可以拋出子類對(duì)象,用基類捕獲,這個(gè)在實(shí)際場景中非常實(shí)用,我們會(huì)在后面詳談
5. 異常的重新拋出
有可能在捕獲異常時(shí),一次捕獲不能完全解決問題,比如我們想在main函數(shù)中處理所有的異常,在非main函數(shù)中打印一下異常信息然后再將異常拋到main中統(tǒng)一做處理
double Division(int a, int b)
{
// 當(dāng)b == 0時(shí)拋出異常
if (b == 0)
{
throw "Division by zero condition!";
}
return (double)a / (double)b;
}
void Func()
{
// 這里可以看到如果發(fā)生除0錯(cuò)誤拋出異常,另外下面的array沒有得到釋放。
// 所以這里捕獲異常后并不處理異常,異常還是交給外面處理,這里捕獲了再
// 重新拋出去。
int* array = new int[10];
try {
int len, time;
cin >> len >> time;
cout << Division(len, time) << endl;
}
catch (...)
{
cout << "delete []" << array << endl;
delete[] array;
throw;
}
cout << "delete []" << array << endl;
delete[] array;
}
int main()
{
try
{
Func();
}
catch (const char* errmsg)
{
cout << errmsg << endl;
}
return 0;
}
在上面的場景中,如果拋出異常,就會(huì)直接走到catch處,不會(huì)調(diào)用delete釋放釋放在堆上開辟的空間,就會(huì)有問題,所以第一次catch時(shí)先處理釋放空間的問題然后將異常再次拋出后再處理異常問題
6. RAII思想在異常體系中的使用
在異常體系中在堆上申請(qǐng)空間,或者打開某個(gè)問題時(shí)常容易出問題,因?yàn)槎焉祥_辟的空間要顯示調(diào)用delete處理而打開的文件也要顯示調(diào)用fclose關(guān)閉所以一旦發(fā)生異常就會(huì)直接跳轉(zhuǎn)到catch的位置,有可能直接忽略了釋放函數(shù)這也就是導(dǎo)致了資源并沒有被釋放!
在異常體系中最好使用RAII思想申請(qǐng)資源
即使拋出異常后直接跳到catch也沒問題
當(dāng)出了對(duì)象作用域會(huì)自動(dòng)調(diào)用析構(gòu)釋放!
double Division(int a, int b)
{
// 當(dāng)b == 0時(shí)拋出異常
if (b == 0)
{
throw "Division by zero condition!";
}
return (double)a / (double)b;
}
void Func()
{
shared_ptr<int> array(new int(10));
try {
int len, time;
cin >> len >> time;
cout << Division(len, time) << endl;
}
}
int main()
{
try
{
Func();
}
catch (const char* errmsg)
{
cout << errmsg << endl;
}
return 0;
}
7. 自定義異常體系
實(shí)際使用中很多公司都會(huì)自定義自己的異常體系進(jìn)行規(guī)范的異常管理,因?yàn)橐粋€(gè)項(xiàng)目中如果大家隨意拋異常,那么外層的調(diào)用者基本就沒辦法玩了,所以實(shí)際中都會(huì)定義一套繼承的規(guī)范體系。這樣大家拋出的都是繼承的派生類對(duì)象,捕獲一個(gè)基類就可以了

不同的部分可以拋出不同的異常,然后在總的main函數(shù)中使用基類捕獲所有的異常再來進(jìn)行特殊的處理
8. C++標(biāo)準(zhǔn)庫的異常體系
這里的內(nèi)容屬于了解范疇,用幾張圖帶大家了解一下:


實(shí)際中都是我們自己去實(shí)現(xiàn)一個(gè)異常體系因?yàn)镃++庫做的并不好
9. 總結(jié)以及拓展
異常總體而言,利大于弊,所以工程中我們還是鼓勵(lì)使用異常的。另外OO的語言基本都是用異常處理錯(cuò)誤,這也可以看出這是大勢(shì)所趨。
除此之外,異常還有一套規(guī)范,因?yàn)楸容^雞肋,所以放在了最后來介紹:
- 異常規(guī)格說明的目的是為了讓函數(shù)使用者知道該函數(shù)可能拋出的異常有哪些。 可以在函數(shù)的后面接throw(類型),列出這個(gè)函數(shù)可能拋擲的所有異常類型。
- 函數(shù)的后面接throw(),表示函數(shù)不拋異常。
- 若無異常接口聲明,則此函數(shù)可以拋擲任何類型的異常。
// 這里表示這個(gè)函數(shù)會(huì)拋出A/B/C/D中的某種類型的異常 void fun() throw(A,B,C,D); // 這里表示這個(gè)函數(shù)只會(huì)拋出bad_alloc的異常 void* operator new (std::size_t size) throw (std::bad_alloc); // 這里表示這個(gè)函數(shù)不會(huì)拋出異常 void* operator delete (std::size_t size, void* ptr) throw(); // C++11 中新增的noexcept,表示不會(huì)拋異常 thread() noexcept; thread (thread&& x) noexcept;
之所以比較雞肋是因?yàn)榫退隳銓懥薾oexcept,再拋出異常,在某些編譯器也不會(huì)報(bào)錯(cuò)
以上就是C++異常處理的方式總結(jié)的詳細(xì)內(nèi)容,更多關(guān)于C++異常處理方式的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C語言實(shí)現(xiàn)食堂就餐管理系統(tǒng)(帶鏈表)
這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)食堂就餐管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-11-11
C++實(shí)現(xiàn)關(guān)機(jī)功能詳細(xì)代碼
大家好,本篇文章主要講的是C++實(shí)現(xiàn)關(guān)機(jī)功能詳細(xì)代碼,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下2022-01-01
c++?qt自定義搜索編輯框的實(shí)現(xiàn)方法
這篇文章主要介紹了c++?qt自定義搜索編輯框,通過自定義QLineEdit,在編輯框里添加布局,將按鈕設(shè)置在右邊,當(dāng)點(diǎn)擊按鈕搜索按鈕時(shí)發(fā)送信號(hào)到主界面做相應(yīng)的操作,需要的朋友可以參考下2022-03-03
C++實(shí)現(xiàn)LeetCode(87.攪亂字符串)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(87.攪亂字符串),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07
C++中靜態(tài)初始化數(shù)組與動(dòng)態(tài)初始化數(shù)組詳解
今天小編就為大家分享一篇C++中靜態(tài)初始化數(shù)組與動(dòng)態(tài)初始化數(shù)組詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-07-07

