【C++11】異常

前言

? ? ? ? 上文我們學習到了C++11中類的新功能【C++11】類的新功能-CSDN博客
????????本文我們來學習C++下一個新語法:異常

1.異常的概念

? ? ? ? 異常的處理機制允許程序在運行時就出現的問題進行相應的處理。異常可以使得我們將問題的發現和問題的解決分開,程序的一部分負責檢測,而另一部分負責處理,檢測環節無需過多的細節。

? ? ? ? 當發生錯誤時,C語言主要通過錯誤碼的形式處理錯誤,錯誤碼本質是將不同的錯誤信息進行編號,拿到錯誤碼我們還需要進行查詢才能得知具體是什么錯誤,比較麻煩。而異常則是拋出一個對象,這個對象可以涵蓋對于這個錯誤的各種信息

2.異常的拋出和捕獲

? ? ? ? 當程序出現問題時,我們將會通過【throw】拋出一個對象來引發一個異常,該對象的類型以及當前的位置決定了由哪個catch來處理。

? ? ? ? 被選中的catch是調用鏈中與給對象類型匹配且離拋出位置最近的那一個。根據拋出異常對象的類型和內容,程序的拋出異常部分會告知到底發生了什么錯誤。

? ? ? ? 當throw執行時,thorw后面的代碼將不再執行,就像break一樣直接跳出。程序的執行從throw的位置直接跳到匹配的catch位置,catch可能在同一個函數中,有可能在調用鏈的其他函數中。這里有兩個注意點:1.沿著調用鏈的函數可能會提前退出 ,2.一旦程序開始執行拋異常,沿著調用鏈創建的對象都將銷毀

? ? ? ? 拋出異常對象后,會產生一個異常對象的臨時對象,因為拋出的異常可能的局部對象。這個臨時對象會在catch語句后銷毀

3.棧展開

? ? ? ? 拋異常后,程序會暫停當前的執行,開始尋找與之匹配的catch子句。首先檢查throw本身是否在try內部,如果在則查找有沒有匹配的catch語句,如果匹配就跳到catch是位置進行處理。

? ? ? ? 如果不匹配或者沒有try內部,則退出當前函數,繼續在外層調用函數鏈中查找,上述過程被稱為棧展開

? ? ? ? 如果一直查找到main函數,依然沒有匹配的catch語句,那么程序就會調用標準庫的terminate函數終止程序

? ? ? ? 如果在后續的查找過程中匹配到了相應的catch語句,那么就執行catch語句以及下面的代碼。

#include<iostream>
#include<string>
using namespace std;double Divide(int a, int b)
{try{//當b為0時拋出異常if (b == 0){string s("除數為0!");throw s;}else{return (double)a / b;}}catch(int errid) //拋異常時,類型不匹配。結束當前函數{cout << errid << endl;}
}void Func()
{int len, time;cin >> len >> time;try{cout << Divide(len, time) << endl;}catch (string errid)//類型匹配,直接跳到這里執行代碼{cout << errid << endl;cout << __FUNCTION__ << ":" << __LINE__ << endl;}}int main()
{while(1){try{Func();}catch (string errid)//類型匹配,但只會跳到最近的catch進行匹配{cout << errid << endl;cout << __FUNCTION__ << ":" << __LINE__ << endl;}}
}
//如果拋異常時,所有catch都不匹配就會報錯,程序停止。

4.查找匹配的處理代碼

? ? ? ? 一般情況下拋出的對象類型要和catch的接收類型完全一樣,如果有多個catch與之匹配,會匹配其最近的catch

? ? ? ? 但是也又特殊情況,允許從非常量向常量的類型轉化,也是就權限縮小。允許數組轉換成指向數組的指針,允許函數轉換成函數指針;允許派生類轉換為基類,這個在實踐中非常常用,一般拋異常都是用這個設計的

? ? ? ? 拋異常的匹配如果到了main函數仍然匹配不上,就會報錯,程序停止。但是一般來說不是發生嚴重的錯誤,我們是不期望程序停止的,所以在main函數的最后我們一般會使用 catch(...),它可以捕捉任意類型的異常,但是并不能知道具體的異常是什么。

????????通過繼承基類實現不同類型是異常,為了統一捕捉在實踐中我們一般都是在main函數中使用catch,try一定要和從catch一起使用

#include<iostream>
#include<thread>
using namespace std;
//每個異常模塊都是繼承Exception的派生類,每個異常模塊都可以添加自己的數據
//最后捕獲的時候,我們捕獲基類就可以了//不同的異常類型都通過繼承基類來實現
class Exception
{
public:Exception(const string& errmsg,int id):_errmsg(errmsg),_id(id){ }virtual string what() const{return _errmsg;}int getid() const{return _id;}protected:string _errmsg;int _id;
};class SqlException : public Exception
{
public:SqlException(const string& errmsg,int id,const string& sql):Exception(errmsg,id),_sql(sql){ }virtual string what() const{string str = "SqlException:";str += _errmsg;str += "->";str += _sql;return str;}private:const string _sql;
};class CacheException : public Exception
{
public:CacheException(const string& errmsg, int id):Exception(errmsg, id){ }virtual string what() const{string str = "CacheException:";str += _errmsg;return str;}
};class HttpException : public Exception
{
public:HttpException(const string& errmsg, int id, const string& type):Exception(errmsg, id), _type(type){}virtual string what() const{string str = "HttpException:";str += _type;str += ":";str += _errmsg;return str;}
private:const string _type;
};void SQLMgr()
{if (rand() % 7 == 0){throw SqlException("權限不足", 100, "select * from name = '張三'");}else{cout << "SQLMgr調用成功" << endl;}
}void CacheMgr()
{if (rand() % 5 == 0){throw CacheException("權限不足", 100);}else if (rand() % 6 == 0){throw CacheException("數據不存在", 101);}else{cout << "CacheMgr 調用成功" << endl;}SQLMgr();
}void HttpServer()
{if (rand() % 3 == 0){throw HttpException("請求資源不存在", 100, "get");}else if (rand() % 4 == 0){throw HttpException("權限不足", 101, "post");}else{cout << "HttpServer調用成功" << endl;}CacheMgr();
}int main()
{srand(time(0));while(1){this_thread::sleep_for(chrono::seconds(1));try{HttpServer();}catch (const Exception& e) //派生類可以向基類進行轉換,這里用基類進行捕獲即可{cout << e.what() << endl;}catch (...)//為防止出現異常不匹配導致程序終止,使用 【...】 進行匹配{cout << "未知異常" << endl;}}
}

5.異常重新拋出

? ? ? ? 有時catch捕捉到一個異常后,需要對錯誤進行分類,對其中某一個錯誤進行特殊處理,而其他的異常要重新拋出給外層調用鏈處理。異常捕獲后,直接使用throw,就可以重新拋出

#include<iostream>
#include<string>
#include<thread>
using namespace std;//以下程序模擬展示聊天時發送消息的情況
//若不是網絡信號導致無法發送,則拋出異常
//若是網絡信號不好時拋出異常,嘗試多次發送class Exception
{
public:Exception(const string& errmsg, int id):_errmsg(errmsg), _id(id){}virtual string what() const{return _errmsg;}int getid() const{return _id;}protected:string _errmsg;int _id;
};class HttpException : public Exception
{
public:HttpException(const string& errmsg, int id, const string& type):Exception(errmsg, id), _type(type){}virtual string what() const{string str = "HttpException:";str += _type;str += ":";str += _errmsg;return str;}
private:const string _type;
};void _SeedMsg(const string& s)
{if (rand() % 2 == 0){throw HttpException("網絡不穩定,發送失敗", 102, "put");}else if (rand() % 7 == 0){throw HttpException("對方不是你好友", 103, "put");}else{cout << "發送成功" << endl;}
}void SeedMsg(const string& s)
{for (int i = 0; i < 4; i++){try{_SeedMsg(s);}catch (Exception& e){if (e.getid() == 102){//重新嘗試if (i == 3){//網絡信號太差,不再過多嘗試,重新拋出throw;}cout << "開始第" << i + 1 << "次嘗試" << endl;}else{//異常重新拋出throw;}}}
}int main()
{srand(time(0));while(1){this_thread::sleep_for(chrono::seconds(1));try{SeedMsg("hello");}catch (Exception& e){cout << e.what() << endl;}}
}

6.異常安全問題

? ? ? ? 當執行throw語句時,throw后面的語句將不再執行。當執行throw這個語句要跳出這個函數去匹配catch,但是這個函數之前申請了空間。這就會造成內存泄漏

? ? ? ? 出現這種情況就需要我們重新捕獲異常,釋放資源后再重新拋出。這種處理方式是不好的,下篇文章我會講到智能指針,使用智能指針來解決這個問題是更好的方法。

7.異常規范

? ? ? ? 對于用戶和編譯器而言,預先知道函數會不會拋異常是很有意義的,這有助于簡化調用函數的代碼。

? ? ? ? C++98中函數后面加 throw( ),表示不會拋異常。函數后面加 throw(類型1,類型2,....),表示可能會拋出異常,如果會拋出多個類型的異常,使用逗號隔開。

? ? ? ? C++11中表示方式會更簡便一些,函數后面加noexcept表示不會拋出異常而函數后面什么都不加則表示可能會拋出異常

? ? ? ? 不過很搞笑的是,如果一個函數后面加了noexcept,但是函數包含throw語句或者包含可能會拋異常的函數,編譯器會順利的編譯通過。但是當這個函數真正拋出異常時,程序會報錯停止。

? ? ? ? noexcept(函數調用表達式) 還可以作為一個運算符,去檢查函數是否可能會拋異常。如果不會拋異常返回true,如果可能會拋異常返回fasle

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

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

相關文章

Linux基礎命令之目錄管理——了解各種操作文件目錄的命令,萬字教學,超詳細!!!(1)

文章目錄 前言1、Linux文件系統1.1 核心特點1.2 重要目錄結構1.3 文件類型1.4 文件和目錄的命名規則1.5 文件與目錄的定位方式 2、查看目錄或文件的詳細信息&#xff08;ls&#xff09;2.1 基本語法2.2 常用操作2.3 高級用法 3、切換目錄&#xff08;cd&#xff09;3.1 常用操作…

在線caj轉換word

CAJ格式是中國知網特有的一種文獻格式&#xff0c;在學術研究等領域廣泛使用&#xff0c;但有時我們需要將其轉換為Word格式&#xff0c;方便編輯、引用文獻。本文分享如何輕松將CAJ轉換為word的轉換工具&#xff0c;提高閱讀和辦公效率。 如何將CAJ轉換WORD? 1、使用CAJ轉換…

【現代深度學習技術】注意力機制05:多頭注意力

【作者主頁】Francek Chen 【專欄介紹】 ? ? ?PyTorch深度學習 ? ? ? 深度學習 (DL, Deep Learning) 特指基于深層神經網絡模型和方法的機器學習。它是在統計機器學習、人工神經網絡等算法模型基礎上&#xff0c;結合當代大數據和大算力的發展而發展出來的。深度學習最重…

SpringBoot 集成滑塊驗證碼AJ-Captcha行為驗證碼 Redis分布式 接口限流 防爬蟲

介紹 滑塊驗證碼比傳統的字符驗證碼更加直觀和用戶友好&#xff0c;能夠很好防止爬蟲獲取數據。 AJ-Captcha行為驗證碼&#xff0c;包含滑動拼圖、文字點選兩種方式&#xff0c;UI支持彈出和嵌入兩種方式。后端提供Java實現&#xff0c;前端提供了php、angular、html、vue、u…

邊緣網關(邊緣計算)

邊緣網關是邊緣計算架構中的關鍵組件&#xff0c;充當連接終端設備&#xff08;如傳感器、IoT設備&#xff09;與云端或核心網絡的橋梁。它在數據源頭附近進行實時處理、分析和過濾&#xff0c;顯著提升效率并降低延遲。 核心功能 協議轉換 ○ 支持多種通信協議&#xff08;如…

OpenCV定位地板上的書

任務目標是將下面的圖片中的書本找出來&#xff1a; 使用到的技術包括&#xff1a;轉灰度圖、提取顏色分量、二值化、形態學、輪廓提取等。 我們嘗試先把圖片轉為灰度圖&#xff0c;然后二值化&#xff0c;看看效果&#xff1a; 可以看到&#xff0c;二值化后&#xff0c;書的…

機器學習第一講:機器學習本質:讓機器通過數據自動尋找規律

機器學習第一講&#xff1a;機器學習本質&#xff1a;讓機器通過數據自動尋找規律 資料取自《零基礎學機器學習》。 查看總目錄&#xff1a;學習大綱 關于DeepSeek本地部署指南可以看下我之前寫的文章&#xff1a;DeepSeek R1本地與線上滿血版部署&#xff1a;超詳細手把手指…

修改圖像分辨率

在這個教程中&#xff0c;您將學習如何使用Python和深度學習技術來調整圖像的分辨率。我們將從基礎的圖像處理技術開始&#xff0c;逐步深入到使用預訓練的深度學習模型進行圖像超分辨率處理。 一、常規修改方法 1. 安裝Pillow庫 首先&#xff0c;你需要確保你的Python環境中…

jsAPI

環境準備 1 安裝nvm nvm 即 (node version manager)&#xff0c;好處是方便切換 node.js 版本 安裝注意事項 要卸載掉現有的 nodejs提示選擇 nvm 和 nodejs 目錄時&#xff0c;一定要避免目錄中出現空格選用【以管理員身份運行】cmd 程序來執行 nvm 命令首次運行前設置好國…

SCDN是什么?

SCDN是安全內容分發網絡的簡稱&#xff0c;它在傳統內容分發網絡&#xff08;CDN&#xff09;的基礎上&#xff0c;集成了安全防護能力&#xff0c;旨在同時提升內容傳輸速度和網絡安全性。 SCDN的核心功能有&#xff1a; DDoS防御&#xff1a;識別并抵御大規模分布式拒絕服務…

Qt/C++開發監控GB28181系統/實時視頻預覽/視頻點播/rtp解包解碼顯示

一、前言 通過gb28181做實時視頻預覽&#xff0c;也就是視頻點播功能&#xff0c;是最重要的功能了&#xff0c;絕對是整個系統排第一重要的&#xff0c;這就是核心功能&#xff0c;什么設備注冊、獲取通道等都是為了實時預覽做準備的&#xff0c;當然這個功能也是最難的&…

找銀子 題解(c++)

題目 思路 首先&#xff0c;這道題乍一看&#xff0c;應該可以用搜索來做。 但是&#xff0c;搜索會不會超時間限制呢&#xff1f; 為了防止時間超限,我們可以換一種做法。 先創立兩個二維數組&#xff0c;一個是輸入的數組a&#xff0c;一個是數組b。 假設 i 行 j 列的數…

子集樹算法文檔

1.算法概述 子集樹是一種 回溯算法&#xff0c;用于生成一個集合的所有子集。給定一個數組 arr&#xff0c;該算法遞歸地遍歷所有可能的子集&#xff0c;并通過一個輔助數組 x 標記當前元素是否被選中。 2.算法特點 時間復雜度&#xff1a;O(2n)&#xff08;因為一個包含 n 個…

HTTP/1.1 host虛擬主機詳解

一、核心需求&#xff1a;為什么需要虛擬主機&#xff1f; 在互聯網上&#xff0c;我們常常希望在一臺物理服務器&#xff08;它通常只有一個公網 IP 地址&#xff09;上運行多個獨立的網站&#xff0c;每個網站都有自己獨特的域名&#xff08;例如 www.a-site.com?, www.b-s…

amass:深入攻擊面映射和資產發現工具!全參數詳細教程!Kali Linux教程!

簡介 OWASP Amass 項目使用開源信息收集和主動偵察技術執行攻擊面網絡映射和外部資產發現。 此軟件包包含一個工具&#xff0c;可幫助信息安全專業人員使用開源信息收集和主動偵察技術執行攻擊面網絡映射并執行外部資產發現。 使用的信息收集技術 技術數據來源APIs&#xf…

Spring Web MVC響應

返回靜態頁面 第一步 創建html時&#xff0c;要注意創建的路徑&#xff0c;要在static下面 第二步 把需要寫的內容寫到body內 第三步 直接訪問路徑就可以 返回數據ResponseBody RestController Controller ResponseBody Controller&#xff1a;返回視圖 ResponseBody&…

?鴻蒙PC正式發布:國產操作系統實現全場景生態突破

鴻蒙PC正式發布&#xff1a;國產操作系統實現全場景生態突破? 2025年5月8日&#xff0c;華為在深圳舉辦發布會&#xff0c;正式推出搭載鴻蒙操作系統的個人電腦&#xff08;PC&#xff09;&#xff0c;標志著國產操作系統在核心技術與生態布局上實現歷史性跨越。此次發布的鴻蒙…

【計算機視覺】OpenCV實戰項目:Text-Extraction-Table-Image:基于OpenCV與OCR的表格圖像文本提取系統深度解析

Text-Extraction-Table-Image&#xff1a;基于OpenCV與OCR的表格圖像文本提取系統深度解析 1. 項目概述2. 技術原理與算法設計2.1 圖像預處理流水線2.2 表格結構檢測算法2.3 OCR優化策略 3. 實戰部署指南3.1 環境配置3.2 核心代碼解析3.3 執行流程示例 4. 常見問題與解決方案4.…

Redis BigKey 問題是什么

BigKey 問題是什么 BigKey 的具體表現是 redis 中的 key 對應的 value 很大&#xff0c;占用的 redis 空間比較大&#xff0c;本質上是大 value 問題。 BigKey怎么找 redis-cli --bigkeysscanBig Key 產生的原因 1.redis數據結構使用不恰當 2.未及時清理垃圾數據 3.對業務預…

go-gin

前置 gin是go的一個web框架&#xff0c;我們簡單介紹一下gin的使用 導入gin &#xff1a;"github.com/gin-gonic/gin" 我們使用import導入gin的包 簡單示例&#xff1a; package mainimport ("github.com/gin-gonic/gin" )func main() {r : gin.Default(…