偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

十點(diǎn)詳解C++異常處理 一文助你全面剖析C++異常處理機(jī)制

開(kāi)發(fā) 后端
在C語(yǔ)言的世界中,對(duì)錯(cuò)誤的處理總是圍繞著兩種方法:一是使用整型的返回值標(biāo)識(shí)錯(cuò)誤;二是使用errno宏(可以簡(jiǎn)單地理解為一個(gè)全局整型變量)去記錄錯(cuò)誤。當(dāng)然C++中仍然是可以用這兩種方法的。

[[389466]]

一,什么是異常處理

一句話:異常處理就是處理程序中的錯(cuò)誤,比如嘗試除以零的操作。

二,為什么需要異常,以及異常處理的基本思想

C++之父Bjarne Stroustrup在《The C++ Programming Language》中講到:一個(gè)庫(kù)的作者可以檢測(cè)出發(fā)生了運(yùn)行時(shí)錯(cuò)誤,但一般不知道怎樣去處理它們(因?yàn)楹陀脩?hù)具體的應(yīng)用有關(guān));另一方面,庫(kù)的用戶(hù)知道怎樣處理這些錯(cuò)誤,但卻無(wú)法檢查它們何時(shí)發(fā)生(如果能檢測(cè),就可以在用戶(hù)的代碼里處理了,不用留給庫(kù)去發(fā)現(xiàn))。

Bjarne Stroustrup說(shuō):提供異常的基本目的就是為了處理上面的問(wèn)題。基本思想是:讓一個(gè)函數(shù)在發(fā)現(xiàn)了自己無(wú)法處理的錯(cuò)誤時(shí)拋出(throw)一個(gè)異常,然后它的(直接或者間接)調(diào)用者能夠處理這個(gè)問(wèn)題。

也就是《C++ primer》中說(shuō)的:將問(wèn)題檢測(cè)和問(wèn)題處理相分離。

一種思想:在所有支持異常處理的編程語(yǔ)言中,要認(rèn)識(shí)到的一個(gè)思想:在異常處理過(guò)程中,由問(wèn)題檢測(cè)代碼可以拋出一個(gè)對(duì)象給問(wèn)題處理代碼,通過(guò)這個(gè)對(duì)象的類(lèi)型和內(nèi)容,實(shí)際上完成了兩個(gè)部分的通信,通信的內(nèi)容是“出現(xiàn)了什么錯(cuò)誤”。當(dāng)然,各種語(yǔ)言對(duì)異常的具體實(shí)現(xiàn)有著或多或少的區(qū)別,但是這個(gè)通信的思想是不變的。

三,異常出現(xiàn)之前處理錯(cuò)誤的方式

在C語(yǔ)言的世界中,對(duì)錯(cuò)誤的處理總是圍繞著兩種方法:一是使用整型的返回值標(biāo)識(shí)錯(cuò)誤;二是使用errno宏(可以簡(jiǎn)單地理解為一個(gè)全局整型變量)去記錄錯(cuò)誤。當(dāng)然C++中仍然是可以用這兩種方法的。

這兩種方法最大的缺陷就是會(huì)出現(xiàn)不一致問(wèn)題。例如有些函數(shù)返回1表示成功,返回0表示出錯(cuò);而有些函數(shù)返回0表示成功,返回非0表示出錯(cuò)。

還有一個(gè)缺點(diǎn)就是函數(shù)的返回值只有一個(gè),你通過(guò)函數(shù)的返回值表示錯(cuò)誤代碼,那么函數(shù)就不能返回其他的值。當(dāng)然,你也可以通過(guò)指針或者C++的引用來(lái)返回另外的值,但是這樣可能會(huì)令你的程序略微晦澀難懂。

四,異常為什么好

優(yōu)點(diǎn)有以下幾點(diǎn):

1. 函數(shù)的返回值可以忽略,但異常不可忽略。如果程序出現(xiàn)異常,但是沒(méi)有被捕獲,程序就會(huì)終止,這多少會(huì)促使程序員開(kāi)發(fā)出來(lái)的程序更健壯一點(diǎn)。而如果使用C語(yǔ)言的error宏或者函數(shù)返回值,調(diào)用者都有可能忘記檢查,從而沒(méi)有對(duì)錯(cuò)誤進(jìn)行處理,結(jié)果造成程序莫名其面的終止或出現(xiàn)錯(cuò)誤的結(jié)果。

2. 整型返回值沒(méi)有任何語(yǔ)義信息。而異常卻包含語(yǔ)義信息,有時(shí)你從類(lèi)名就能夠體現(xiàn)出來(lái)。

3. 整型返回值缺乏相關(guān)的上下文信息。異常作為一個(gè)類(lèi),可以擁有自己的成員,這些成員就可以傳遞足夠的信息。

異常處理可以在調(diào)用跳級(jí)。這是一個(gè)代碼編寫(xiě)時(shí)的問(wèn)題:假設(shè)在有多個(gè)函數(shù)的調(diào)用棧中出現(xiàn)了某個(gè)錯(cuò)誤,使用整型返回碼要求你在每一級(jí)函數(shù)中都要進(jìn)行處理。而使用異常處理的棧展開(kāi)機(jī)制,只需要在一處進(jìn)行處理就可以了,不需要每級(jí)函數(shù)都處理。

五, C++中使用異常時(shí)應(yīng)注意的問(wèn)題

任何事情都是兩面性的,異常有好處就有壞處。如果在你的代碼中使用異常,那么需要注意以下事項(xiàng):

1. 性能問(wèn)題。這個(gè)一般不會(huì)成為瓶頸,但是如果你編寫(xiě)的是高性能或者實(shí)時(shí)性要求比較強(qiáng)的軟件,就需要考慮了。

2. 指針和動(dòng)態(tài)分配導(dǎo)致的內(nèi)存回收問(wèn)題:動(dòng)態(tài)內(nèi)存不會(huì)自動(dòng)回收,如果遇到異常就需要考慮是否正確地回收了內(nèi)存。

函數(shù)的異常拋出列表:如果沒(méi)有寫(xiě)noexcept,意味著你可以拋出任何異常。

六,異?;菊Z(yǔ)法

很簡(jiǎn)單,拋出一場(chǎng)用throw,捕獲用try...catch

  • throw: 當(dāng)問(wèn)題出現(xiàn)時(shí),程序會(huì)拋出一個(gè)異常。
  • catch: 在您想要處理問(wèn)題的地方,通過(guò)異常處理程序捕獲異常。
  • try: try 塊中的代碼標(biāo)識(shí)將被激活得特定異常。它后面通常跟著一個(gè)或多個(gè) catch 塊。
  • noexcept:用于聲明函數(shù)不拋出異常,如果函數(shù)拋了異常,則直接中斷,不能被捕獲

使用 try...catch 語(yǔ)句的語(yǔ)法如下所示:

  1. try 
  2.    // 保護(hù)代碼 
  3. }catch( ExceptionName e1 ) 
  4.    // catch 塊 
  5. }catch( ExceptionName e2 ) 
  6.    // catch 塊 
  7. }catch( ExceptionName eN ) 
  8.    // catch 塊 

 如果 try 塊在不同的情境下會(huì)拋出不同的異常,這個(gè)時(shí)候可以嘗試羅列多個(gè) catch 語(yǔ)句,用于捕獲不同類(lèi)型的異常

捕獲異常時(shí)的注意事項(xiàng):

  1. catch的匹配過(guò)程是找最先匹配的,不是最佳匹配。
  2. catch的匹配過(guò)程中,對(duì)類(lèi)型的要求比較嚴(yán)格。不允許標(biāo)準(zhǔn)算術(shù)轉(zhuǎn)換和類(lèi)類(lèi)型的轉(zhuǎn)換。(類(lèi)類(lèi)型的轉(zhuǎn)化包括兩種:通過(guò)構(gòu)造函數(shù)的隱式類(lèi)型轉(zhuǎn)化和通過(guò)轉(zhuǎn)化操作符的類(lèi)型轉(zhuǎn)化)。

七,異常之棧解旋

異常被拋出后,從進(jìn)入try塊起,到異常被拋擲前,這期間在棧上構(gòu)造的所有對(duì)象,都會(huì)被自動(dòng)析構(gòu)。

析構(gòu)的順序與構(gòu)造的順序相反,這一過(guò)程稱(chēng)為棧的解旋(unwinding).

  1. struct Maker 
  2.     Maker() 
  3.     { 
  4.         cout << "Maker() 構(gòu)造函數(shù)" << endl; 
  5.     } 
  6.     Maker(const Maker& other) 
  7.     { 
  8.         cout << "Maker(Maker&) 拷貝構(gòu)造函數(shù)" << endl; 
  9.     } 
  10.     ~Maker() 
  11.     { 
  12.         cout << "~Maker() 析構(gòu)函數(shù)" << endl; 
  13.     } 
  14. }; 
  15. void fun() 
  16.     Maker m; 
  17.     cout << "--------" << endl; 
  18.     throw m; 
  19.     cout << "fun__end" << endl; 
  20. int main() 
  21.     try 
  22.     { 
  23.         fun(); 
  24.     } 
  25.     catch (Maker & m) 
  26.     { 
  27.         cout << "收到Maker異常" << endl; 
  28.     } 

 八,C++ 標(biāo)準(zhǔn)的異常

C++ 提供了一系列標(biāo)準(zhǔn)的異常,定義在 中,我們可以在程序中使用這些標(biāo)準(zhǔn)的異常。它們是以父子類(lèi)層次結(jié)構(gòu)組織起來(lái)的,如下所示:


每個(gè)類(lèi)所在的頭文件在圖下方標(biāo)識(shí)出來(lái)

標(biāo)準(zhǔn)異常類(lèi)的成員: ① 在上述繼承體系中,每個(gè)類(lèi)都有提供了構(gòu)造函數(shù)、復(fù)制構(gòu)造函數(shù)、和賦值操作符重載。 ② logic_error類(lèi)及其子類(lèi)、runtime_error類(lèi)及其子類(lèi),它們的構(gòu)造函數(shù)是接受一個(gè)string類(lèi)型的形式參數(shù),用于異常信息的描述; ③ 所有的異常類(lèi)都有一個(gè)what()方法,返回const char* 類(lèi)型(C風(fēng)格字符串)的值,描述異常信息。

下表是對(duì)上面層次結(jié)構(gòu)中出現(xiàn)的每個(gè)異常的說(shuō)明:

九、編寫(xiě)自己的異常類(lèi)

  • 為什么要編寫(xiě)自己的異常類(lèi)? ① 標(biāo)準(zhǔn)庫(kù)中的異常是有限的; ② 在自己的異常類(lèi)中,可以添加自己的信息。(標(biāo)準(zhǔn)庫(kù)中的異常類(lèi)值允許設(shè)置一個(gè)用來(lái)描述異常的字符串)。
  • 如何編寫(xiě)自己的異常類(lèi)? ① 建議自己的異常類(lèi)要繼承標(biāo)準(zhǔn)異常類(lèi)。因?yàn)镃++中可以拋出任何類(lèi)型的異常,所以我們的異常類(lèi)可以不繼承自標(biāo)準(zhǔn)異常,但是這樣可能會(huì)導(dǎo)致程序混亂,尤其是當(dāng)我們多人協(xié)同開(kāi)發(fā)時(shí)。 ② 當(dāng)繼承標(biāo)準(zhǔn)異常類(lèi)時(shí),應(yīng)該重載父類(lèi)的what函數(shù)和虛析構(gòu)函數(shù)。 ③ 因?yàn)闂U归_(kāi)的過(guò)程中,要復(fù)制異常類(lèi)型,那么要根據(jù)你在類(lèi)中添加的成員考慮是否提供自己的復(fù)制構(gòu)造函數(shù)。

示例:

  1. #include <iostream> 
  2. #include <exception> 
  3. using namespace std; 
  4.  //第一種 
  5. class Out_Range : public exception 
  6. public
  7.     explicit Out_Range(const string& _Message) : exception(_Message.c_str()) {} 
  8.     explicit Out_Range(const char* _Message) : exception(_Message) {} 
  9. }; 
  10. //第二種 
  11. struct Exce :public exception 
  12.     const char* what() const override 
  13.     { 
  14.         return "Exce"
  15.     } 
  16. }; 
  17.   
  18. void foo(int arr[], int len) 
  19.     int i = -1; 
  20.     if (i<0 || i>=len) 
  21.     { 
  22.         throw Out_Range("數(shù)組越界啦~"); 
  23.     } 
  24.     cout << arr[i] << endl; 
  25.  
  26. int main() 
  27.     int arr[3] = { 0 }; 
  28.     try 
  29.     { 
  30.         foo(arr, 3); 
  31.     } 
  32.     catch (Out_Range& e)        //自定義錯(cuò)誤 
  33.     { 
  34.         cout << "Out_Range& e   " << e.what() << endl; 
  35.     } 
  36.     catch (std::exception& e)   //其他錯(cuò)誤 
  37.     { 
  38.         cout <<"std::exception& e   "<<e.what()<< endl; 
  39.     } 
  40.     return 0; 

 十,來(lái)自C++之父Bjarne Stroustrup的建議

節(jié)選自《The C++ Programming Language》 ——C++之父Bjarne Stroustrup

1. 當(dāng)局部的控制能夠處理時(shí),不要使用異常;

2.使用“資源分配即初始化”技術(shù)去管理資源;

3. 盡量少用try-catch語(yǔ)句塊,而是使用“資源分配即初始化”技術(shù)。

4. 如果構(gòu)造函數(shù)內(nèi)發(fā)生錯(cuò)誤,通過(guò)拋出異常來(lái)指明。

5. 避免在析構(gòu)函數(shù)中拋出異常。

6. 保持普通程序代碼和異常處理代碼分開(kāi)。

7. 小心通過(guò)new分配的內(nèi)存在發(fā)生異常時(shí),可能造成內(nèi)存泄露。

8. 如果一個(gè)函數(shù)可能拋出某種異常,那么我們調(diào)用它時(shí),就要假定它一定會(huì)拋出該異常,即要進(jìn)行處理。

9. 要記住,不是所有的異常都繼承自exception類(lèi)。

10. 編寫(xiě)的供別人調(diào)用的程序庫(kù),不應(yīng)該結(jié)束程序,而應(yīng)該通過(guò)拋出異常,讓調(diào)用者決定如何處理(因?yàn)檎{(diào)用者必須要處理拋出的異常)。

 

責(zé)任編輯:姜華 來(lái)源: 今日頭條
相關(guān)推薦

2015-12-28 11:25:51

C++異常處理機(jī)制

2011-03-17 09:20:05

異常處理機(jī)制

2010-01-27 15:36:54

C++異常處理

2009-08-05 18:09:17

C#異常處理機(jī)制

2011-04-06 10:27:46

Java異常處理

2010-01-27 15:29:45

C++異常處理

2010-02-02 11:16:28

C++異常

2010-01-13 13:42:55

C++編譯器

2010-03-05 15:40:16

Python異常

2009-08-31 17:26:32

C#異常處理

2010-01-27 16:39:48

C++編譯器

2024-02-27 10:48:16

C++代碼開(kāi)發(fā)

2011-08-19 15:05:29

異常處理

2023-11-13 17:01:26

C++編程

2011-07-21 15:20:41

java異常處理機(jī)制

2023-06-15 14:09:00

解析器Servlet容器

2024-01-22 13:05:00

C++編程異常處理

2010-01-22 18:33:17

C++編譯器

2021-07-03 17:53:52

Java異常處理機(jī)制

2024-03-04 10:00:35

數(shù)據(jù)庫(kù)處理機(jī)制
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)