異常c/c++

目錄

1.c語言傳統處理錯誤方式

1、終止程序

2、返回錯誤碼

2.c++異常概念

3.異常的使用

?3.1異常的拋出與捕獲

3.2異常安全(還有一些異常重新拋出)

3.3異常規范

4.自定義異常體系

5.c++標準庫的異常體系

6.異常優缺點

?1、優點

2、缺點

7、補充


1.c語言傳統處理錯誤方式

1、終止程序

如assert斷言、內存錯誤(原因有很多,越界訪問啊等等)、除0錯誤

2、返回錯誤碼

錯誤碼,常見的就是程序運行后,如果沒有錯誤的話,就是返回0,不正常的時候返回負的多少或者其他奇怪的數字。很多庫的接口函數都把錯誤碼放到errno中,表示錯誤。遇到這種,錯誤的原因需要查表或者自行尋找到錯誤原因。

2.c++異常概念

?異常在很多面向對象的語言都有,python也有。

異常是一種處理錯誤的方式,可以理解為程度比assert輕一點,處理方式不是粗暴的終止程序。當出現某個編譯器無法處理的錯誤時,可以將其作為異常拋出,由程序員預先設置的程序來處理這個錯誤。

throw:拋出異常,“throw 字符串或數字”

catch:捕獲異常,比如捕獲到了字符串或數字,就會進入對應的塊域中,執行設定的語句。可以多個catch捕獲多個異常(比如針對字符串的、針對數字的)

try:在try里面的語句,都會在運行時進行檢查,如果遇到異常,把異常拋出后,會馬上跳到catch中。

try
{// 保護的標識代碼
}catch( ExceptionName e1 )
{// catch 塊
}catch( ExceptionName e2 )
{// catch 塊
}catch( ExceptionName eN )
{// catch 塊
}
void fa() {int a; cin >> a;if (a == 2){throw "wdawd";}else if (a == 3){throw 4;}else if (a == 4){string s("dwwdawda");throw s;}else if (a == 5){stack<int>s;s.push(2);throw s;}
}int main()
{try {fa();}catch (const char* err){cout << err << endl;}catch (int x){cout << x << endl;}catch (const string& es){cout << es << endl;}catch (...) {cout << 231231 << endl;}return 0;
}

如果沒有遇到異常,在執行完try里面的語句后,會直接跳過catch里面的內容。

注意,如果是庫里的對象返回的話,建議用const 類型&來接受,因為這樣如果這個對象有移動拷貝的話,這個寫法可以接受右值也可以接受左值,提高效率。

3.異常的使用

?3.1異常的拋出與捕獲

相比c語言傳統的錯誤碼(遇到錯誤,要層層返回,每層都要處理,直到返回main函數),異常可以直接跳回到匹配的catch處。這個過程中,跳過的函數都是會正常銷毀的

異常拋出和匹配原則

1、異常是通過拋出對象引出的,該對象的類型決定了應該激活哪個catch

2、被選中的處理代碼是調用鏈(就是從main到第一個函數到其內的函數再到其內的函數,一路下去)中與對象類型匹配且距離拋出異常的位置最近的,比如在第一個函數處也有try,然后執行try里面的內容時拋了異常,并且catch的內容與拋出的對象的類型是匹配的,那就會執行第一個函數處的對應catch而不是main函數處的catch。

3、catch(...)可以捕獲任意類型的異常,問題是不知道異常是什么? ?用來兜底的,建議一定加

4、拋出異常后,對于相應的對象,會生成該對象的拷貝,因為這個對象可能是個臨時對象(比如局部變量),這個拷貝出來的對象,在catch之后會銷毀。(效率還是很高的,因為臨時對象的話,走移動拷貝,效率挺高的)。比如我們拋出了一個string對象,就上面的代碼中一樣。

5、類型不一定嚴格匹配,可以拋出派生類對象,讓基類捕獲,利用多態。具體看下面的異常體系

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

1、throw拋出后,要確認自己是否在try里面,在的話才去找匹配的catch,然后跳到匹配的catch處

2、沒有匹配的catch,就跳出當前的函數棧,在調用該函數的函數棧中繼續找匹配的catch

3、如果在main函數中都沒有找到匹配的catch就會終止程序。而整個沿著調用鏈向上找匹配的catch的過程,就是棧展開。所以實際中,我們都會加個catch(...),否則有異常沒捕獲就會直接終止程序。

4、在匹配的catch處執行完對應的語句后,會沿著當前的try ....catch之后的語句繼續執行

3.2異常安全(還有一些異常重新拋出)

異常安全的核心問題就是在調用鏈非常長的情況下,異常會直接跳到catch,而這個過程很可能橫跨了很多個函數。

1、不要在構造函數里拋異常,因為拋異常會直接跳到catch。如果構造函數里面要進行初始化,最典型的就是開辟多段空間給多個指針變量,如果這個過程中拋異常了,導致有些指針變量沒有被初始化,仍然是野指針或空指針,那么析構函數在delete或者free的時候就會拋異常或者報錯。簡單點就是說可能會造成對象不完整或者沒有完全初始化

2、析構函數不要拋異常。因為析構函數負責資源的清理,如果在析構函數中拋異常,很可能導致內存泄漏等問題,比如某個空間沒有被delete掉。

3、異常經常會導致內存泄漏的問題。比如new和delete中間有一塊拋出了異常,導致直接跳到catch了,delete就不會執行,這樣就內存泄漏了,還會導致lock和unlock之間的死鎖問題(這個是線程的知識,看我linux和網絡的部分即可)

接下來是一種處理方法,利用異常重新拋出

void fa() {int a; cin >> a;if (a == 2){throw "wdawd";}else if (a == 3){throw 4;}else if (a == 4){string s("dwwdawda");throw s;}else if (a == 5){stack<int>s;s.push(2);throw s;}
}
void f() {int* x = new int;try {fa();}catch (...) {//不一定是...,只是最保險的就是這個,不管拋了什么異常都可以接受delete x;throw;//不管接受到什么異常,都通通重新拋出去。}
}
int main()
{try {f();}catch (const char* err){cout << err << endl;}catch (int x){cout << x << endl;}catch (const string& es){cout << es << endl;}catch (...) {cout << 231231 << endl;}return 0;
}

核心思路就是在關鍵位置提前捕獲,然后再重新拋出

比較惡心的情況:

void f() {int* x = new int;int *x1,x2;try {x1 = new int;try {x2 = new int;}catch (...) {delete x1;delete x;throw;}}catch (...) {delete x;throw;}delete x;delete x1;delete x2;
}

這個方法寫起來太麻煩了,可見這個方法也不是很好,依靠智能指針可以更加的高效處理這個問題

class SmartPtr {
public:SmartPtr(int *ptr):_ptr(ptr){}~SmartPtr() {delete _ptr;}
private:int* _ptr;
};
void f() {SmartPtr s1(new int);SmartPtr s2(new int);SmartPtr s3(new int);//這樣就可以依靠析構函數自動清理資源了。//就算拋了異常,s1、s2、s3是局部變量,在出了作用域會自動銷毀,調用它的析構函數}

3.3異常規范

出于上面的情況,98的時候,希望大家寫異常的時候規范一些。

// 這里表示這個函數會拋出A/B/C/D中的某種類型的異常
void fun() throw(A,B,C,D);
// 這里表示這個函數只會拋出A的異常
void* operator new (std::size_t size) throw (A);
// 這里表示這個函數不會拋出異常
void* operator delete (std::size_t size, void* ptr) throw();單單靠上面3個,還是會出問題,比如寫了拋abc,但實際上可能拋了d。
又比如函數深層調用,一層調一層那豈不是每一層函數都要寫好多的throw()。
而且因為考慮到兼容c語言的問題,這只能是個建議而不是規定。// C++11 中新增的noexcept,表示不會拋異常
thread() noexcept;
thread (thread&& x) noexcept;//通過這個簡化,只標記不會拋異常的函數。
但要小心的是,間接層加了noexcept,但這層函數調用的函數拋了異常,是不會檢測到的。而且一旦檢測到拋出了規定外的異常,編譯器也只是報錯。

4.自定義異常體系

在實際過程中,大家都是設計一個異常體系,否則的下不同組各自管自己拋異常,最后害慘了外面管異常的,因為catch(...)是不確定究竟是什么異常,所以通過設計異常體系,讓異常的信息更加的準確,方便處理。

?接下來是一個比較常見的異常體系

class Exception
{
public:Exception(const string& errmsg, int id):_errmsg(errmsg), _id(id){}virtual string what() const{return _errmsg;   //返回錯誤描述  }
protected:string _errmsg;//錯誤描述,比如基礎的錯誤信息,比如內存錯誤等等int _id; //錯誤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 HttpServerException : public Exception
{
public:HttpServerException(const string& errmsg, int id, const string& type):Exception(errmsg, id), _type(type){}virtual string what() const{string str = "HttpServerException:";str += _type;str += ":";str += _errmsg;return str;}
private:const string _type;
};

那么如何捕獲呢?

catch (const Exception& e) // 這里捕獲父類對象就可以{// 多態cout << e.what() << endl;}

利用繼承的特性,用父類對象的引用來接受派生類或者父類本身。

然后利用虛函數的特性,在滿足多態的情況下,如果接受的派生類,那么what調用的就是派生類的what,如果接受的是父類,就會調用父類的what。

5.c++標準庫的異常體系

?c++標準庫也是弄了一個異常體系。

圖片出自菜鳥編程。

6.異常優缺點

?1、優點

1、相比傳統的錯誤碼,異常可以更加清晰的展現出錯誤的信息,甚至包含堆棧的調用信息,這樣可以幫助更好的定位bug

2、錯誤碼必須通過層層的retrun返回錯誤碼,然后才能拿到錯誤碼,相比之下異常可以直接拿到信息,跳過中間的過程。

3、很多第三方的庫都包含了異常,使用的時候也得關注異常。

4、部分情況用異常更好,比如構造函數沒有返回值,只能拋異常。比如at這個函數,返回什么很重要,但問題是返回什么都可能不是錯誤信息,反而可能是一個正常的值,但確實下標越界了。

2、缺點

1、異常會導致程序的執行流亂跳,會非常混亂,尤其是運行時的時候拋異常就會亂跳。導致調試跟蹤以及分析程序的時候會非常困難。

2、異常有一定的性能開銷,不過在現在的硬件下,基本可以忽略不計。

3、c++沒有垃圾回收機制,資源需要自己管理,容易造成內存泄漏、死鎖等異常安全問題,想要解決,建議是rall(智能指針的內容)。

4、標準庫的異常體系定義的一般,導致所有人都是各自定義各自的,比較混亂。

5、異常需要盡量的規范使用,否則負責捕獲異常處理異常的人會很痛苦。主要是,所有的異常繼承自一個基類;函數是否拋異常、拋什么異常,都使用func() throw()的形式規范

7、補充

異常一旦發生,說明程序出現了非法的情況
程序中只要有異常,就必須處理。一旦有拋出異常,那么必須捕獲,否則代碼最后會崩潰。

基類的const類型引用,可以捕獲所有的子類的異常對象
?

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

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

相關文章

ChatGPT 提示詞框架

作為一個資深安卓開發工程師&#xff0c;我們在日常開發中經常會用到 ChatGPT 來提升開發效率&#xff0c;比如代碼優化、bug 排查、生成單元測試等。 但要想真正發揮 ChatGPT 的潛力&#xff0c;我們需要掌握一些提示詞&#xff08;Prompt&#xff09;的編寫技巧&#xff0c;并…

面試基礎---JVM 運行時數據區

深入理解 JVM 運行時數據區&#xff1a;從源碼到實踐 在現代互聯網大廠的開發環境中&#xff0c;Java 依然是主流語言之一&#xff0c;而 Java 虛擬機&#xff08;JVM&#xff09;作為 Java 程序運行的基礎&#xff0c;其性能和穩定性直接關系到應用的表現。因此&#xff0c;深…

PostgreSQL 查看數據庫及表中數據占用空間大小

1、應用場景 場景1&#xff1a;查看數據庫占用空間大小 SELECT pg_size_pretty(pg_database_size(database_name));場景2&#xff1a;查看每張表占用空間大小 SELECTtable_schema || . || table_name AS table,#僅表數據pg_size_pretty(pg_relation_size(table_schema || . …

c++中打印任意類型任意長度數組的各種方式

目錄 一、代碼 二、詳細解釋 1. print 函數模板 2. array_size 函數模板 3. print1 函數模板 4. print2 函數模板 5. my_begin 和 my_end 函數模板 6. print3 函數模板 7. main 函數 總結 一、代碼 如下代碼給出了5種方式打印任意類型任意長度的數組。這段代碼定義了…

ubuntu下r8125網卡重啟丟失修復案例一則

剛裝的一臺服務器&#xff0c;ubuntu24.04&#xff0c;主板網卡是r8125&#xff0c;安裝服務后會莫名其妙丟失驅動 按照官網的方法下載最新8125驅動包&#xff1a; Realtek 然后卸載驅動 rmmod r8125 然后在驅動包里安裝&#xff08;幸好我之前裝了build-essential&#x…

[Python學習日記-84] 進程理論

[Python學習日記-84] 進程理論 簡介 進程的概念 并發與并行的區別 進程并發的實現 簡介 進程理論是計算機科學中一種重要的概念&#xff0c;用來描述操作系統中執行的程序實例。在操作系統中&#xff0c;每個程序的執行被稱為一個進程。進程理論研究進程的創建、調度、通信…

云創智城YunCharge 新能源二輪、四輪充電解決方案(云快充、萬馬愛充、中電聯、OCPP1.6J等多個私有單車、汽車充電協議)之新能源充電行業系統說明書

云創智城YunCharge 新能源充電行業系統說明書 ?官方文檔 ?官網地址 1. 引言 隨著全球環境保護和能源危機的加劇&#xff0c;新能源汽車行業得到了快速發展&#xff0c;充電基礎設施建設也隨之蓬勃發展。新能源充電行業系統旨在提供高效、便捷的充電服務&#xff0c;滿足電…

OpenWebUI配置異常的外部模型導致頁面無法打開

一、使用Ollama關閉OpenAI OpenWebUI自帶OpenAI的API設置&#xff0c;且默認是打開的&#xff0c;默認情況下&#xff0c;啟動后&#xff0c;會不斷的去連https://api.openai.com/v1&#xff0c;但是無法連上&#xff0c;會報錯&#xff0c;但是不會影響頁面&#xff0c;能正常…

RuntimeWarning: invalid value encountered in scalar power在進行標量的冪運算時遇到了無效值

year_profit ((profit / initial_cash) ** (1 / yy) - 1) * 100 RuntimeWarning: invalid value encountered in scalar power 這個警告表示在執行標量冪運算 ((profit / initial_cash) ** (1 / yy) - 1) * 100 時遇到了無效值。常見的引發原因及解決辦法如下&#xff1a; ###…

計算機畢業設計 ——jspssm506Springboot 的舊物置換網站

&#x1f4d8; 博主小檔案&#xff1a; 花花&#xff0c;一名來自世界500強的資深程序猿&#xff0c;畢業于國內知名985高校。 &#x1f527; 技術專長&#xff1a; 花花在深度學習任務中展現出卓越的能力&#xff0c;包括但不限于java、python等技術。近年來&#xff0c;花花更…

Kafka消費者相關

Kafka生產者相關-CSDN博客 消費者消費數據基本流程 package com.hrui;import org.apache.kafka.clients.consumer.ConsumerConfig; import org.apache.kafka.clients.consumer.ConsumerRecord; import org.apache.kafka.clients.consumer.ConsumerRecords; import org.apache…

【軟考-架構】備戰2025軟考

新老教材對比 科目1&#xff08;信息系統綜合&#xff09;考點詳解 科目2&#xff08;系統架構設計案例&#xff09;考點詳解 科目3&#xff08;系統架構設計論文&#xff09;考點詳解 趨于越來越具體 學習方法推薦 第一階段 – 基礎知識階段 建議一個半月&#xff1b; 先過…

MMW-1碳棒磨損機設計

摘 要 為了更好的測量在一定壓力下碳棒的磨損量&#xff0c;提高碳棒磨損量的測量精度&#xff0c;本文設計了一種MMW-1碳棒磨損機&#xff0c;該碳棒磨損機屬于柱盤式摩擦磨損試驗機的一種。該機器主要用于做和碳棒有關的摩擦磨損試驗&#xff0c;可以更準確的獲得相關的參數…

網絡運維學習筆記(DeepSeek優化版)005網工初級(HCIA-Datacom與CCNA-EI)鏈路層發現協議與VLAN技術

文章目錄 一、鏈路層發現協議1.1 思科CDP協議1.2 華為LLDP協議 二、VLAN&#xff08;Virtual Local Area Network&#xff0c;虛擬局域網&#xff09;技術詳解2.1 基本概念2.2 技術特性2.3 接口工作原理2.3.1 Access模式2.3.2 Trunk模式 2.4 廠商配置對比思科配置華為配置 2.5 …

SOME/IP-SD -- 協議英文原文講解5

前言 SOME/IP協議越來越多的用于汽車電子行業中&#xff0c;關于協議詳細完全的中文資料卻沒有&#xff0c;所以我將結合工作經驗并對照英文原版協議做一系列的文章。基本分三大塊&#xff1a; 1. SOME/IP協議講解 2. SOME/IP-SD協議講解 3. python/C舉例調試講解 5.1.2.5 S…

APNG格式圖片文件大小優化方案 轉WEBP

文章目錄 原因過程相關下載相關文檔后記 原因 頁面上有個特效動畫&#xff0c;PNG文件&#xff0c;APNG格式&#xff0c;13M大小&#xff0c;太占用內容了&#xff0c;要優化一下。 過程 直接上命令吧 ffmpeg -i input.apng -vf "formatrgba" -loop 0 output.web…

個人電腦小參數GPT預訓練、SFT、RLHF、蒸餾、CoT、Lora過程實踐——MiniMind圖文版教程

最近看到Github上開源了一個小模型的repo&#xff0c;是真正拉低LLM的學習門檻&#xff0c;讓每個人都能從理解每一行代碼&#xff0c; 從零開始親手訓練一個極小的語言模型。開源地址&#xff1a; GitHub - jingyaogong/minimind: &#x1f680;&#x1f680; 「大模型」2小時…

PHP Zip 文件處理指南

PHP Zip 文件處理指南 引言 ZIP文件是一種流行的壓縮格式&#xff0c;廣泛用于文件壓縮和歸檔。PHP作為一門強大的服務器端腳本語言&#xff0c;提供了豐富的類和方法來處理ZIP文件。本文將詳細介紹PHP中ZIP文件的處理方法&#xff0c;包括創建、添加文件、提取文件以及壓縮和…

Java使用ZXing庫生成帶有Logo的二維碼圖片,并去除白邊動態伸縮上傳到阿里云OSS

文章目錄 引言二維碼基本原理1、二維碼概述2、QR Code結構3、錯誤糾正級別 QR Code生成技術1、ZXing庫2、生成二維碼的步驟 圖像處理技術1、嵌入Logo2. 去除白邊 阿里云OSS基本概念1、OSS概述2. 主要功能3. 基本概念 實戰演示1、依賴庫2、類結構3、生成普通二維碼4. 去除白邊5、…

AI工具箱最新使用教程

先克隆項目 電腦需要先安裝 git &#xff0c;安裝的畫看這個 Git安裝教程&#xff08;超詳細&#xff09;。 git鏡像 git clone https://github.com/Escaflowne1985/MyToolsWebBackendUser.gitgitee鏡像 git clone https://gitee.com/escaflowne/MyToolsWebBackendUser.git…