柚子快報邀請碼778899分享:【C++】異常
柚子快報邀請碼778899分享:【C++】異常
1. 概念
異常是一種處理錯誤的方式,當(dāng)一個函數(shù)發(fā)現(xiàn)自己無法處理的錯誤時就可以拋出異常,讓函數(shù)的
直接或間接的調(diào)用者處理這個錯誤
代碼舉例
#include
using namespace std;
int division(int x,int y)
{
if (y == 0)
{
throw "除0錯誤";
}
return x / y;
}
int main()
{
try
{
int x, y;
cin >> x >> y;
division(x, y);
}
catch (const char* e)
{
cout << e << endl;
}
return 0;
}
運行結(jié)果:
注:
throw: 當(dāng)問題出現(xiàn)時,程序會拋出一個異常,這是通過使用 throw 關(guān)鍵字來完成的
catch: 在您想要處理問題的地方,通過異常處理程序捕獲異常.catch 關(guān)鍵字用于捕獲異
常,可以有多個catch進行捕獲
try: try 塊中的代碼標(biāo)識將被激活的特定異常,它后面通常跟著一個或多個 catch 塊
2. 使用
a. 異常的拋出和捕獲
(一)異常的拋出和匹配原則
異常是通過拋出對象而引發(fā)的,該對象的類型決定了應(yīng)該激活哪個catch的處理代碼被選中的處理代碼是調(diào)用鏈中與該對象類型匹配且離拋出異常位置最近的那一個
代碼舉例
#include
#include
using namespace std;
int divsion(int x,int y)
{
if (y == 0)
{
throw "除數(shù)不能為 0";
}
return x / y;
}
void func()
{
try
{
int x, y;
cin >> x >> y;
divsion(x, y);
}
catch(const char* x)
{
cout << "func()" << endl;
cout << x;
}
}
int main()
{
try
{
func();;
}
catch (const char* x)
{
cout << " main()" << endl;
cout << x;
}
return 0;
}
運行結(jié)果:
throw 拋出的異常對應(yīng)的是最里面的循環(huán)鏈
拋出異常對象后,會生成一個異常對象的拷貝,因為拋出的異常對象可能是一個臨時對象,
所以會生成一個拷貝對象,這個拷貝的臨時對象會在被catch以后銷毀(這里的處理類似
于函數(shù)的傳值返回)
? ? ?2.? catch(...)可以捕獲任意類型的異常,問題是不知道異常錯誤是什么
代碼舉例
#include
#include
using namespace std;
int divsion(int x,int y)
{
if (y == 0)
{
throw "除數(shù)不能為 0";
}
return x / y;
}
int main()
{
try
{
int x, y;
cin >> x >> y;
divsion(x, y);
}
catch (const char* x)
{
cout << "func()" << endl;
cout << x;
}
catch (...)
{
cout << "未知錯誤" << endl;
}
return 0;
}
3. 實際中拋出和捕獲的匹配原則有個例外,并不都是類型完全匹配,可以拋出的派生類對象,?
使用基類捕獲
(二)在函數(shù)調(diào)用鏈中異常棧展開匹配原則
首先檢查throw本身是否在try塊內(nèi)部,如果是再查找匹配的catch語句,如果有匹配的,則
調(diào)到catch的地方進行處理
? ? ? 2.? 沒有匹配的catch則退出當(dāng)前函數(shù)棧,繼續(xù)在調(diào)用函數(shù)的棧中進行查找匹配的catch
? ? ? 3.? 如果到達main函數(shù)的棧,依舊沒有匹配的,則終止程序。上述這個沿著調(diào)用鏈查找匹配的
catch子句的過程稱為棧展開。所以實際中我們最后都要加一個catch(...)捕獲任意類型的異常,否則當(dāng)有異常沒捕獲,程序就會直接終止
? ? ?4.? 找到匹配的catch子句并處理以后,會繼續(xù)沿著catch子句后面繼續(xù)執(zhí)行
b. 異常的重新拋出
有可能單個的catch不能完全處理一個異常,在進行一些校正處理以后,希望再交給更外層的調(diào)用
鏈函數(shù)來處理,catch則可以通過重新拋出將異常傳遞給更上層的函數(shù)進行處理
代碼舉例
#include
using namespace std;
int Division(int a, int b)
{
if (b == 0)
{
throw "除數(shù)不能為0";
}
return a / b;
}
void Func()
{
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* arr)
{
cout << arr << endl;
}
return 0;
}
運行結(jié)果:
3. 異常安全
構(gòu)造函數(shù)完成對象的構(gòu)造和初始化,最好不要在構(gòu)造函數(shù)中拋出異常,否則可能導(dǎo)致對象不
完整或沒有完全初始化
? ? ?2.? 析構(gòu)函數(shù)主要完成資源的清理,最好不要在析構(gòu)函數(shù)內(nèi)拋出異常,否則可能導(dǎo)致資源泄漏
? ? ?3.? C++中異常經(jīng)常會導(dǎo)致資源泄漏的問題,比如在new和delete中拋出了異常,導(dǎo)致內(nèi)存泄
漏,C++經(jīng)常使用RAII(資源回收)來解決以上問題
4. 異常規(guī)范
異常規(guī)格說明的目的是為了讓函數(shù)使用者知道該函數(shù)可能拋出的異常有哪些, 可以在函數(shù)的
后面接throw(類型),列出這個函數(shù)可能拋擲的所有異常類型
? ? ?2.? 函數(shù)的后面接throw(),表示函數(shù)不拋異常 (c++11 喜歡寫成 noexcpet 表示絕對不會拋異常)
? ? ?3.? 若無異常接口聲明,則此函數(shù)可以拋擲任何類型的異常
5. C++標(biāo)準(zhǔn)庫的異常體系
C++ 提供了一系列標(biāo)準(zhǔn)的異常,我們可以在程序中使用這些標(biāo)準(zhǔn)的異常。它們是以父
子類層次結(jié)構(gòu)組織起來的
注:
因為C++標(biāo)準(zhǔn)庫設(shè)計的不夠好用,所以實際中很多公司像上面一樣自己定義一套異常繼承體系
柚子快報邀請碼778899分享:【C++】異常
相關(guān)文章
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。