深入了解C++異常處理
基本的異常處理
異常處理機制:暫緩問題處理,不在當(dāng)前函數(shù)中處理,在他的調(diào)用者中處理(先上車,后補票)
什么是異常:任何東西都可以認為是異常,錯誤只是異常的一種
異常一旦被拋出,不做處理,如果引發(fā)異常,會調(diào)用默認abort函數(shù)終止程序
捕獲和處理異常:
throw 拋出異常: (值是任何類型都可以,只是我們處理異常的一個參照,類似返回值)
try(檢查,捕獲)和catch(處理異常): 必須是一起出現(xiàn),并且它們的括號{ }不能省略
tip:? ?任何東西都可以認為是異常,錯誤只是異常中的一種---出現(xiàn)一種情況不能讓程序正常運行

怎么拋出異常
//求a和b的余數(shù) 怎么拋出異常
int division(int a,int b){
if(b==0)
throw 0; //拋出一個值(任意)--->之后處理
return a/b;
}
void print(int a,int b){
cout<<division(a,b);
}
int main(){
print(1,0);
}
/* 把b==0 的情況稱為異常,b==0 時代碼不成立,會調(diào)用默認abort函數(shù)終止程序 */
異常一旦被拋出,不做處理,如果引發(fā)異常,會調(diào)用默認abort函數(shù)終止程序?

捕獲和處理異常
//try 與catch必須是一起出現(xiàn),并且他們的括號{}不能省略
try
{
//正常需要檢查是否存在異常的代碼
}
catch(類型) //理解為switch中case語句
{
//處理是根據(jù)拋出數(shù)據(jù)類型決定如何處理 匹配項 匹配拋出異常的類型
}
//一個try可以對應(yīng)多個catch
try
{
//...
}
catch(int)
{
}
catch(double)
{
}
catch(string)
{
}
//catch和if else_if 執(zhí)行機制是一樣的,只能執(zhí)行一個匹配項
小知識:
- 對try{ }? ?catch(){ } 的理解:在當(dāng)前位置引發(fā)異常,直接從這個位置跳到catch的位置執(zhí)行catch的代碼 --- 類似switch case 語句
- catch中int和char不會做轉(zhuǎn)換
- 寫兩個相同的類型不被允許,哪段代碼先引發(fā)異常就先調(diào)用catch
int division(int a,int b){
if(b==0)
throw 0;
return a/b;
}
void print(int a,int b){
cout<<division(a,b);
}
int main(){
try
{
print(1,0); //檢查異常
cout<<"別的代碼"<<endl; //這一句不會運行,會直接跳到catch
}
catch(int) //拋出的是int類型,捕獲int類型
{
cout<<"除數(shù)不能為0"<<endl;
}
}
程序能拋出(存在)多個異常,但是只能同時處理1個異常,不能同時引發(fā)多個異常
不存在異常的描述 --- 標(biāo)識性作用? ??
- throw ()
- noexcept
//某個函數(shù)不存在異常,在某個函數(shù)后面用throw() 描述,表示它不存在異常
void print() throw()
{
cout << "當(dāng)前函數(shù)不存在拋出異常操作" << endl;
}
void printData() noexcept
{
cout << "c++新標(biāo)準(zhǔn)中的關(guān)鍵字: 不存在拋出異常操作" << endl;
//throw 0; 一旦說明沒有異常操作,就不能拋出
}
刪減符 ...
任何類型的異常都捕獲? ? 不管拋出啥,在哪里拋出的,只要引發(fā)異常都可以捕獲到
catch(...)
{
cout <<"捕獲任何類型的異常"<< endl;
}
異常處理中的傳參操作? --- 可以寫一個變量進去
catch(int a)/* 隱藏了一個傳參操作 可以傳任何類型,包括自定義類型都可以 */
注意c++中string的處理? ? /* string類型與const char* 類型區(qū)別 */
代碼解析:
對? 通過拋出字符串,隱藏了一個傳參操作? 的理解
int divisor(int a, int b)
{
if (b == 0)
throw string("除數(shù)不能為0");
return a / b;
}
int main()
{
try
{
divisor(1, 0);
}
catch (string str) //把throw的內(nèi)容賦值給str str="除數(shù)不能為0"
{
cout << str << endl;
}
}
注意string類型與const char* 類型區(qū)別? --- 出現(xiàn)類型不匹配,c++對傳參類型要求更嚴(yán)格
int divisor(int a, int b)
{
if (b == 0)
throw "除數(shù)不能為0"; //拋出異常 解析為char* 類型 寫catch時不能直接當(dāng)作string
if(b==1)
throw "除數(shù)不能為1"; /* 不同問題的拋出,不能用固定類型(int、char...), 可以選擇
拋出不同字符串處理 string1,string2,string3... 通過傳
參的方式去描述問題 */
if(b==2)
throw string("除數(shù)不能為2"); //需構(gòu)造無名參數(shù)作捕獲對象處理--->需要自己觸發(fā)
return a / b;
}
int main()
{
try
{
divisor(1, 0); //直接觸發(fā)異常
}
catch (const char* str) //拋出的是char* 類型,不能當(dāng)作string
{
cout << str << endl;
}
try
{
divisor(1, 2);
}
catch (string str) //如果要捕獲string類型,需要自己構(gòu)造一個string對象返回
{
cout << str << endl; //直接輸出str
}
}
可以拋出自己類的對象
class Error
{
public:
Error(const char* str = "未知錯誤") :str(str) {}
const char* what()const
{
return str.c_str();
}
protected:
string str;
};
void insertArray(int array[], int* curNum, int posData,int maxLength)
{
if (*curNum >= maxLength) //3>=3
{
throw Error("數(shù)組下標(biāo)溢出!");
}
//0 1 2
array[*curNum] = posData; //array[3]=3
(*curNum)++;
}
int main(){
try
{
int array[3] = { 0,0,0 };
int curNum = 0;
for (int i = 0; i < 4; i++)
{
insertArray(array, &curNum, i, 3);
}
}
catch (Error str)
{
cout << str.what() << endl;
}
return 0;
}
標(biāo)準(zhǔn)庫當(dāng)中的異常類
#include<exception> //父類(基類)
子類很多,子類描述的問題不同而已
例子: const char* _ptr; 一個數(shù)據(jù)成員,用于描述標(biāo)準(zhǔn)庫當(dāng)中異常的字符串,用字符指針存放那個字符串
what( )方法? 用于返回數(shù)據(jù)成員的? ? ? ? 1.虛函數(shù)? ? ? ? 2.不存在異常
return _ptr ? _ptr : "unknow";判斷char* 類型的指針是不是為空,不等于空,返回你描述的錯誤,等于空(由于沒有傳參),返回未知錯誤"unknow"





引發(fā)標(biāo)準(zhǔn)庫中內(nèi)存申請失敗的異常
發(fā)現(xiàn)代碼出現(xiàn)abort( )錯誤,可以通過這種方式找到,這里是針對內(nèi)存申請失敗做了單一處理,如果不做處理,會直接調(diào)用abort函數(shù)終止程序
#include <exception>
#include <iostream>
using namespace std;
class Exception
{
public:
Exception(const char* ptr="UNKNOW") :ptr(const_cast<char*>(ptr)){} /*構(gòu)造函數(shù) 干掉
常屬性*/
virtual const char* what() const //父類是虛函數(shù) 且不存在異常
{
return ptr;
}
protected:
char* ptr;
};
//子類繼承父類
class Bad_alloc :public Exception
{
public:
Bad_alloc(const char* _Message = "bad exception") :Exception(_Message) {} /*調(diào)用父類
的構(gòu)造函數(shù)拋出bad exception*/
protected:
};
//子類繼承父類 調(diào)用父類構(gòu)造函數(shù)
class Run_time :public Exception
{
public:
Run_time(const char* _Message = "run_time error") :Exception(_Message) {}
protected:
};
int main()
{
try
{
while (1)
{
int* p = new int[1024*1024*10];//一直做內(nèi)存申請,不做釋放,最后一定會內(nèi)存申請失敗
}
}
catch (bad_alloc& object) /* 內(nèi)存申請失敗,調(diào)用bad_alloc 標(biāo)準(zhǔn)庫中的異常,創(chuàng)建一個對象接收一
下,子類中的what()方法調(diào)用父類中的what()方法打印 */
{
cout << object.what() << endl;
}
return 0;
}
/*輸出*/
bad allocation //調(diào)用時拋出 bad allocation 是子類對象調(diào)用繼承下來的what()方法
//一般寫代碼出現(xiàn)莫名的中斷,原因是不做異常處理,引發(fā)了abort函數(shù)中斷程序,一般這種錯誤都是特殊錯誤
標(biāo)準(zhǔn)庫中傳兩個參數(shù)起到標(biāo)識作用,由于:引發(fā)了不同的錯誤,不同錯誤對應(yīng)了不同的錯誤編碼 對這些錯誤有特定的描述 ---> 工具 ---> 錯誤查找 ---> 輸入錯誤編碼

值:3
錯誤信息:系統(tǒng)找不到指定的路徑?
以上就是深入了解C++異常處理的詳細內(nèi)容,更多關(guān)于C++異常處理的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C語言二叉樹常見操作詳解【前序,中序,后序,層次遍歷及非遞歸查找,統(tǒng)計個數(shù),比較,求深度】
這篇文章主要介紹了C語言二叉樹常見操作,結(jié)合實例形式詳細分析了基于C語言的二叉樹前序,中序,后序,層次遍歷及非遞歸查找,統(tǒng)計個數(shù),比較,求深度等相關(guān)操作技巧與注意事項,需要的朋友可以參考下2018-04-04
詳解如何在C/C++中測量一個函數(shù)或功能的運行時間
本文算是一個比較完整的關(guān)于在 C/C++ 中測量一個函數(shù)或者功能的總結(jié),最后會演示三種方法的對比,文章通過代碼示例給大家介紹的非常詳細,需要的朋友可以參考下2023-12-12
C/C++?Qt?TreeWidget?單層樹形組件應(yīng)用小結(jié)
TreeWidget?目錄樹組件,該組件適用于創(chuàng)建和管理目錄樹結(jié)構(gòu),在開發(fā)中我們經(jīng)常會把它當(dāng)作一個升級版的ListView組件使用,本文將通過TreeWidget實現(xiàn)多字段顯示,并增加一個自定義菜單,通過在指定記錄上右鍵可彈出該菜單并對指定記錄進行操作2021-11-11

