【C++】C++異常語法、使用、規范、異常安全及異常的優缺點

1. C++異常概念

異常是一種處理錯誤的方式,當一個函數發現自己無法處理的錯誤時就可以拋出異常,讓函數的直接或間接的調用者處理這個錯誤。

  • throw: 當問題出現時,程序會拋出一個異常。這是通過使用 throw 關鍵字來完成的。
  • catch: 在您想要處理問題的地方,通過異常處理程序捕獲異常.catch 關鍵字用于捕獲異常,可以有多個catch進行捕獲。
  • try: try 塊中的代碼標識將被激活的特定異常,它后面通常跟著一個或多個 catch 塊。

如果有一個塊拋出一個異常,捕獲異常的方法會使用 try 和 catch 關鍵字。try 塊中放置可能拋出異常的代碼,try 塊中的代碼被稱為保護代碼。使用 try/catch 語句的語法如下所示:

try
{//可能會出現異常的代碼塊//即保護的標識代碼
}
catch(ExceptionName e1)
{//catch快
}
catch(ExceptionName e2)
{//catch快
}
catch(ExceptionName eN)
{//catch快
}

2.異常的拋出和匹配原則

  1. 異常是通過拋出對象而引發的,該對象的類型決定了應該激活哪個catch的處理代碼。
  2. 選中的處理代碼是調用鏈中與該對象類型匹配且離拋出異常位置最近的那一個。
  3. 拋出異常對象后,會生成一個異常對象的拷貝,因為拋出的異常對象可能是一個臨時對象,所以會生成
    一個拷貝對象,這個拷貝的臨時對象會在被catch以后銷毀。(這里的處理類似于函數的傳值返回)
  4. catch(…)可以捕獲任意類型的異常,問題是不知道異常錯誤是什么。
  5. 實際中拋出和捕獲的匹配原則有個例外,并不都是類型完全匹配,可以拋出的派生類對象,使用基類捕獲,這個在實際中非常實用,我們后面會詳細講解這個
  6. 對于以上特性,為加深對其理解,代碼解析如下:
double Division(int a, int b)
{// 當b == 0時拋出異常if (b == 0)//拋出char*類型字符串類型,則必須匹配對應//的類型來catch//拋出的異常會生成一個臨時對象的拷貝//因為本層函數棧幀馬上就要結束了!!!throw "Division by zero condition!";elsereturn ((double)a / (double)b);
}
void Func1()
{try{int len, time;cin >> len >> time;cout << Division(len, time) << endl;}//發生異常,如果能與本層的catch匹配,則在本層函數棧幀拋異常//若果不能與本層函數棧幀的catch匹配,則結束本層函數棧幀,//去上一層函數棧幀繼續匹配,直到main函數,//如果還不能匹配異常,則直接終止程序catch (int errid){cout << errid << endl;}
}
int main()
{try {Func1();}catch (const char* errmsg){cout << errmsg << endl;}catch (int errid) {cout << errid << endl;}catch (...){cout << "unkown exception" << endl;}return 0;
}

3.在函數調用鏈中異常棧展開匹配原則

  1. 首先檢查throw本身是否在try塊內部,如果是再查找匹配的catch語句。如果有匹配的,則調到catch的地方進行處理。
  2. 沒有匹配的catch則退出當前函數棧,繼續在調用函數的棧中進行查找匹配的catch。
  3. 如果到達main函數的棧,依舊沒有匹配的,則終止程序。上述這個沿著調用鏈查找匹配的catch子句的過程稱為棧展開。所以實際中我們最后都要加一個catch(…)捕獲任意類型的異常,否則當有異常沒捕獲,程序就會直接終止。
  4. 找到匹配的catch子句并處理以后會繼續沿著catch子句后面繼續執行
    以上匹配原則的圖片理解方式如下所示:
    在這里插入圖片描述

4.異常的重新拋出

有可能單個的catch不能完全處理一個異常,在進行一些校正處理以后,希望再交給更外層的調用鏈函數來處理,catch則可以通過重新拋出將異常傳遞給更上層的函數進行處理.如下代碼示例所示:

double Division(int a, int b)
{// 當b == 0時拋出異常if (b == 0){throw "Division by zero condition!";}return (double)a / (double)b;
}
void Func()
{// 這里可以看到如果發生除0錯誤拋出異常,另外下面的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;
}

5.異常安全

  1. 構造函數完成對象的構造和初始化,最好不要在構造函數中拋出異常,否則可能導致對象不完整或沒有完全初始化
  2. 析構函數主要完成資源的清理,最好不要在析構函數內拋出異常,否則可能導致資源泄漏(內存泄漏、句柄未關閉等)
  3. C++中異常經常會導致資源泄漏的問題,比如在new和delete中拋出了異常,導致內存泄漏,在lock和unlock之間拋出了異常導致死鎖C++經常使用RAII來解決以上問題。(關于RAII智能指針,可以觀看我的RAII智能篇)

6.異常規則

  1. 異常規格說明的目的是為了讓函數使用者知道該函數可能拋出的異常有哪些。 可以在函數的后面接throw(類型),列出這個函數可能拋擲的所有異常類型。
  2. C++98中函數的后面接throw(),表示函數不拋異常。C++11中函數的后面接except(),表示函數不拋異常。
  3. 若無異常接口聲明,則此函數可以拋擲任何類型的異常。
// 這里表示這個函數會拋出A/B/C/D中的某種類型的異常
void fun() throw(A,B,C,D);
// 這里表示這個函數只會拋出bad_alloc的異常
void* operator new (std::size_t size) throw (std::bad_alloc);
// 這里表示這個函數不會拋出異常
void* operator new (std::size_t size, void* ptr) throw()/noexcept();

7.C++標準庫中的異常體系

C++ 提供了一系列標準的異常,定義在 中,我們可以在程序中使用這些標準的異常。它們是以父子類層次結構組織起來的,如下所示:
在這里插入圖片描述
說明: 實際中我們可以可以去繼承exception類實現自己的異常類。但是實際中很多公司像上面一樣自己定義一套異常繼承體系。因為C++標準庫設計的不夠好用。如下代碼示例:

int main()
{try{vector<int> v(10, 5);// 這里如果系統內存不夠也會拋異常v.reserve(1000000000);// 這里越界會拋異常v.at(10) = 100; }catch (const exception& e) // 這里捕獲父類對象就可以{cout << e.what() << endl;}catch (...){cout << "Unkown Exception" << endl;}return 0;
}

8.異常的優缺點(面試有面到!!!)

C++異常的優點:

  1. 異常對象定義好了,相比錯誤碼的方式可以清晰準確的展示出錯誤的各種信息,甚至可以包含堆棧調用的信息,這樣可以幫助更好的定位程序的bug。
  2. 返回錯誤碼的傳統方式有個很大的問題就是,在函數調用鏈中,深層的函數返回了錯誤,那么我們得層層返回錯誤,最外層才能拿到錯誤,具體看下面的詳細解釋。
// 1.下面這段偽代碼我們可以看到ConnnectSql中出錯了,
// 先返回給ServerStart,ServerStart再
//返回給main函數,main函數再針對問題處理具體的錯誤。
// 2.如果是異常體系,不管是ConnnectSql
// 還是ServerStart及調用函數出錯,都不用檢查,因為拋
//出的異常異常會直接跳到main函數中catch捕獲的地方,main函數直接處理錯誤。
int ConnnectSql()
{// 用戶名密碼錯誤if (...)return 1;// 權限不足if (...)return 2;
}
int ServerStart() {if (int ret = ConnnectSql() < 0)return ret;int fd = socket()if(fd < 0return errno;
}
int main()
{if (ServerStart() < 0)...return 0;
}
  1. 很多的第三方庫都包含異常,比如boost、gtest、gmock等等常用的庫,那么我們使用它們也需要使用異常。
  2. 很多測試框架都使用異常,這樣能更好的使用單元測試等進行白盒的測試。
  3. 部分函數使用異常更好處理,比如構造函數沒有返回值,不方便使用錯誤碼方式處理。比如T&operator這樣的函數,如果pos越界了只能使用異常或者終止程序處理,沒辦法通過返回值表示錯誤。

C++異常的缺點:

  1. 異常會導致程序的執行流亂跳,并且非常的混亂,并且是運行時出錯拋異常就會亂跳。這會導致我們跟蹤調試時以及分析程序時,比較困難。
  2. 異常會有一些性能的開銷。當然在現代硬件速度很快的情況下,這個影響基本忽略不計。
  3. C++沒有垃圾回收機制,資源需要自己管理。有了異常非常容易導致內存泄漏、死鎖等異常安全問題。這個需要使用RAII來處理資源的管理問題。學習成本較高。
  4. C++標準庫的異常體系定義得不好,導致大家各自定義各自的異常體系,非常的混亂。
  5. 異常盡量規范使用,否則后果不堪設想,隨意拋異常,外層捕獲的用戶苦不堪言。所以異常規范有兩點:一、拋出異常類型都繼承自一個基類。二、函數是否拋異常、拋什么異常,都使用 func()throw();的方式規范化。
    總結: 異常總體而言,利大于弊,所以工程中我還是鼓勵使用異常的。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/213359.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/213359.shtml
英文地址,請注明出處:http://en.pswp.cn/news/213359.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

給你的Python程序添點Emoji魔法:使用Emoji模塊增添趣味和個性!

當你想給你的Python程序增添一些趣味和個性時&#xff0c;Emoji模塊是一個很有用的工具。Emoji模塊允許你在Python中使用各種表情符號&#xff0c;從笑臉到動物&#xff0c;甚至是食物和天氣等。在本篇博客中&#xff0c;我們將介紹如何在Python中使用Emoji模塊&#xff0c;并展…

【小白專用】使用PHP創建和操作MySQL數據庫,數據表

php數據庫操作 php連接mysql數據庫 <?php $hostlocalhost; // 數據庫主機名 $username"root"; // 數據庫用戶名 $password"al6"; // 數據庫密碼 $dbname"mysql"; // 數據庫名 $connIDmysqli_connect($host,$username,$password,$dbn…

adb push報錯:remote couldn‘t create file: Is a directory

adb push報錯&#xff1a;remote couldn‘t create file: Is a directory 出現這個問題可能是電腦本地目錄中包含中文或者是目錄地址中多包含了一個/ 比如說以下兩種路徑 1. test/測試音頻文件1/a.mp3 2.test/test_audio/ 這兩種都是不可以的&#xff08;我是在as中執行的…

MQTT服務質量-QoS

QoS是消息發送方和接收方之間的協議&#xff0c;定義了指定消息發送保證等級。本文將深入探究MQTT中不同的QoS等級。 QoS是什么 MQTT提供三個QoS等級&#xff1a; 最多一次&#xff08;QoS 0&#xff09;至少一次&#xff08;QoS 1&#xff09;確切一次&#xff08;QoS 2&am…

科技提升安全,基于YOLOv5系列模型【n/s/m/l/x】開發構建商超扶梯場景下行人安全行為姿態檢測識別系統

在商超等人流量較為密集的場景下經常會報道出現一些行人在扶梯上摔倒、受傷等問題&#xff0c;隨著AI技術的快速發展與不斷普及&#xff0c;越來越多的商超、地鐵等場景開始加裝專用的安全檢測預警系統&#xff0c;核心工作原理即使AI模型與攝像頭圖像視頻流的實時計算&#xf…

2024年JAVA招聘行情如何?

大家都在說Java求職不好找&#xff0c;是真的嗎&#xff1f;我們來看看數據。 數據支持&#xff1a;根據TIOBE 5月份的編程語言排行榜&#xff0c;Java仍然是前三名之一。這意味著&#xff0c;Java在開發領域仍然占據重要地位。 而在中國的IT市場中&#xff0c;Java仍然是主要…

使用alpine鏡像部署go應用時踩的坑

使用alpine鏡像部署go應用時踩的坑 關于交叉編譯 實際上我在ubuntu的交叉編譯出來的exe并不能在alpine上運行&#xff0c;這邊采取拉鏡像編譯復制出來的做法&#xff0c;部署再用干凈的alpine 拉取golang:alpine踩坑 在Dockerhub上可以找到&#xff1a; 然而拉取的alpine中…

在普通的項目中創建web的功能

新增web功能: 1.創建一個新項目&#xff0c;不勾選模板&#xff1a;2.添加web功能&#xff1a; 1.創建一個新項目&#xff0c;不勾選模板&#xff1a; 發現普通項目沒有webapp文件夾&#xff0c;即沒有web的功能。 2.添加web功能&#xff1a; Add framework support:添加一些…

VHDL數碼管顯示控制器設計

題目要求&#xff1a; 初始狀態&#xff0c;開關 K1 為低電平&#xff0c;6 個數碼管上依次顯示 1-6。當 K1 變為高電平時&#xff0c;數據管顯示內容依次循環左移&#xff0c;當 K1 變為低電平時&#xff0c;保持當前顯示內容。 參考資料&#xff1a;使用VHDL實現動態掃描八位…

luceda ipkiss教程 45:在版圖上加LOGO

**在設計版圖時往往需要加上公司或者學校的LOGO,只需要LOGO的圖片&#xff0c;通過代碼就可以將LOGO加到版圖上&#xff0c;比如&#xff1a; ** 通過代碼可以得到版圖上的LOGO: ! 代碼如下&#xff1a; from si_fab import all as pdk from ipkiss3 import all as i3i3.TECH…

國際驗證碼有哪些具體的應用場景?

用戶注冊 在許多網站和應用程序中&#xff0c;用戶注冊是必要的第一步。通過使用驗證碼接口&#xff0c;可以防止惡意機器人或自動化程序大規模注冊賬號&#xff0c;從而保護網站或應用程序的安全性和可靠性。 密碼重置 當用戶忘記密碼或需要重置密碼時&#xff0c;驗證碼可…

MyBatis逆向工程

正向工程&#xff1a;先創建Java實體類&#xff0c;由框架負責根據實體類生成數據庫表。Hibernate是支持正向工程的。逆向工程&#xff1a;先創建數據庫表&#xff0c;由框架負責根據數據庫表&#xff0c;反向生成如下資源&#xff1a; Java實體類Mapper接口Mapper映射文件 1…

apply call bind三者區別區別

apply call bind三者區別區別 三者的相同點&#xff1a;都是用來改變this的指向 call()和apply()的區別&#xff1a; 相同點&#xff1a;都是調用一個對象的一個方法&#xff0c;用另一個對象替換當前對象&#xff08;功能相同&#xff09; B.call(A, args1,args2);即A對象調用…

docker的基本管理和概念

docker是什么&#xff1f; docker是開源的應用容器引擎。基于go語言開發的。運行在Linux系統中的開源的輕量級的“虛擬機”。 docker的容器技術可以在一臺主機上輕松的為任何應用創建一個輕量級的、可移植的、自給自足的容器 docker的宿主機是linux系統。集裝箱可以理解為相互…

CAN總線協議編程實例

1. can.h #ifndef __CAN_H #define __CAN_H#include "./SYSTEM/sys/sys.h"/******************************************************************************************/ /* CAN 引腳 定義 */#define CAN_RX_GPIO_PORT GPIOA #define CAN_RX_GPI…

R2RNet: Low-light Image Enhancement viaReal-low to Real-normal Network

本研究針對在弱光條件下拍攝的圖像可能嚴重降低圖像質量的問題進行了探索。解決一系列低光圖像的退化可以有效提高圖像的視覺質量和高級視覺任務的性能。在本研究中&#xff0c;我們提出了一種新穎的基于Retinex的真實低光到真實正常光網絡&#xff08;R2RNet&#xff09;&…

Vue自定義指令插槽作用域插槽具名插槽

Vue自定義指令&插槽&作用域插槽&具名插槽 一、學習目標 1.自定義指令 基本語法&#xff08;全局、局部注冊&#xff09;指令的值v-loading的指令封裝 2.插槽 默認插槽具名插槽作用域插槽 3.綜合案例&#xff1a;商品列表 MyTag組件封裝MyTable組件封裝 4.路…

小紅書筆記投流全攻略,打造爆款內容

在小紅書平臺上&#xff0c;信息流投放和搜索廣告是兩種主要的廣告形式。信息流投放主要通過用戶刷作品時展示你的筆記&#xff0c;而搜索廣告則是用戶搜索相關關鍵詞時展示出的內容。今天就和大家分享下小紅書筆記投流全攻略&#xff0c;打造爆款內容&#xff01; 一、什么樣你…

探秘ipa文件簽名工具在線簽名工具:工作原理和代碼表示原理

隨著iOS應用程序的興起&#xff0c;ipa文件的安全性變得越來越重要。為了確保應用程序來源的可信度和完整性&#xff0c;開發者需要對其應用進行簽名&#xff0c;并使用正確的證書來驗證其身份。在這篇文章中&#xff0c;我們將探索一個名為在線簽名工具的ipa文件簽名工具&…

【JavaWeb筆記】單選框,結合Servlet

各個部分的作用 jsp部分 form action"..."&#xff1a;表單標簽&#xff0c;供用戶提交數據。內部的submit點擊之后相當于是點action的URL input type"radio"&#xff1a;輸入類型為單選框。把name設置為一樣的&#xff0c;這樣效果上就是單選&#xff…