最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++ 程序拋出異常后執(zhí)行順序說(shuō)明

 更新時(shí)間:2021年02月24日 14:27:08   作者:無(wú)鞋童鞋  
這篇文章主要介紹了C++ 程序拋出異常后執(zhí)行順序說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧

1 析構(gòu)函數(shù)中是否可以拋出異常

首先我們看一個(gè)常見(jiàn)的問(wèn)題,析構(gòu)函數(shù)中是否可以拋出異常。答案是C++標(biāo)準(zhǔn)指明析構(gòu)函數(shù)不能、也不應(yīng)該拋出異常!

C++異常處理模型是為C++語(yǔ)言量身設(shè)計(jì)的,更進(jìn)一步的說(shuō),它實(shí)際上也是為C++語(yǔ)言中面向?qū)ο蠖?wù)的。

C++異常處理模型最大的特點(diǎn)和優(yōu)勢(shì)就是對(duì)C++中的面向?qū)ο筇峁┝俗顝?qiáng)大的無(wú)縫支持。

那么如果對(duì)象在運(yùn)行期間出現(xiàn)了異常,C++異常處理模型有責(zé)任清除那些由于出現(xiàn)異常所導(dǎo)致的已經(jīng)失效了的對(duì)象(也即對(duì)象超出了它原來(lái)的作用域),并釋放對(duì)象原來(lái)所分配的資源, 這就是調(diào)用這些對(duì)象的析構(gòu)函數(shù)來(lái)完成釋放資源的任務(wù),所以從這個(gè)意義上說(shuō),析構(gòu)函數(shù)已經(jīng)變成了異常處理的一部分。

下面我們來(lái)看看析構(gòu)函數(shù)中不能拋出異常的兩個(gè)理由:

1)如果析構(gòu)函數(shù)拋出異常,則異常點(diǎn)之后的程序不會(huì)執(zhí)行,如果析構(gòu)函數(shù)在異常點(diǎn)之后執(zhí)行了某些必要的動(dòng)作比如釋放某些資源,則這些動(dòng)作不會(huì)執(zhí)行,會(huì)造成諸如資源泄漏的問(wèn)題。

2)通常異常發(fā)生時(shí),c++的機(jī)制會(huì)調(diào)用已經(jīng)構(gòu)造對(duì)象的析構(gòu)函數(shù)來(lái)釋放資源,此時(shí)若析構(gòu)函數(shù)本身也拋出異常,則前一個(gè)異常尚未處理,又有新的異常,會(huì)造成程序崩潰的問(wèn)題。

那么當(dāng)無(wú)法保證在析構(gòu)函數(shù)中不發(fā)生異常時(shí), 該怎么辦?

其實(shí)還是有很好辦法來(lái)解決的。那就是把異常完全封裝在析構(gòu)函數(shù)內(nèi)部,決不讓異常拋出函數(shù)之外。這是一種非常簡(jiǎn)單,也非常有效的方法。

//析構(gòu)函數(shù)
~Class()
{
 try{
 }
 catch(){ //這里可以什么都不做,只是保證catch塊的程序拋出的異常不會(huì)被扔出析構(gòu)函數(shù)之外。
 }
}

2 程序拋出異常后會(huì)怎樣

下面我們通過(guò)一個(gè)程序來(lái)觀察當(dāng)程序中拋出異常了是否會(huì)調(diào)用析構(gòu)函數(shù),異常拋出中throw()后面的語(yǔ)句是否還會(huì)執(zhí)行。

程序如下,我們創(chuàng)建一個(gè)類(lèi),然后構(gòu)造一個(gè)類(lèi)對(duì)象,當(dāng)拋出異常我們看程序是否會(huì)進(jìn)入析構(gòu)函數(shù)以及throw()拋出異常后面的程序:

#include<iostream>
using namespace std;
class setTry{
public:
 setTry(){ //構(gòu)造函數(shù)
  cout << "start!" << endl; // 1
 }
 ~setTry(){ //析構(gòu)函數(shù)
  cout << "end!" << endl; // 4
 }
 void dosomething(){
  cout << "do something!" << endl; //類(lèi)方法
 }
};
int main(void)
{
 setTry newOne;
 try{
  throw("error!"); //直接拋出異常 
  newOne.dosomething();
 }
 catch (char* one){ //接收char*類(lèi)異常 
  cout << one << endl; // 2
 }
 catch (...){   //接收其他類(lèi)型異常
  cout << "..." << endl;
 }
 cout << "return 0!"<<endl; // 3
 return 0;
}

上面程序運(yùn)行結(jié)就是按標(biāo)注的1、2、3、4步驟輸出的,結(jié)果如下圖所示:

從運(yùn)行結(jié)果就可以看出,拋出異常try內(nèi)部的throw()后面程序不會(huì)再執(zhí)行,而try外部后面的程序會(huì)繼續(xù)執(zhí)行。另外,析構(gòu)函數(shù)在生存期結(jié)束也會(huì)被調(diào)用。

補(bǔ)充:C++異常捕獲和處理

0. 寫(xiě)在前面

異常,讓一個(gè)函數(shù)可以在發(fā)現(xiàn)自己無(wú)法處理的錯(cuò)誤時(shí)拋出一個(gè)異常,希望它的調(diào)用者可以直接或者間接處理這個(gè)問(wèn)題。而傳統(tǒng)錯(cuò)誤處理技術(shù),檢查到一個(gè)錯(cuò)誤,返回退出碼或者終止程序等等,此時(shí)我們只知道有錯(cuò)誤,但不能更清楚的知道哪種錯(cuò)誤,因此,使用異常,就把錯(cuò)誤和處理分開(kāi)來(lái),由庫(kù)函數(shù)拋出異常,由調(diào)用者捕獲這個(gè)異常,調(diào)用者就可以知道程序函數(shù)庫(kù)調(diào)用出現(xiàn)錯(cuò)誤了,并去處理,而是否終止程序就把握在調(diào)用者手里了。

1. 異常的拋出和處理

1. 異常處理的語(yǔ)句

try區(qū)段:這個(gè)區(qū)段中包含了可能發(fā)生異常的代碼,在發(fā)生了異常之后,需要通過(guò)throw拋出。

throw子句:throw 子句用于拋出異常,被拋出的異??梢允荂++的內(nèi)置類(lèi)型(例如: throw int(1);),也可以是自定義類(lèi)型。

catch子句:每個(gè)catch子句都代表著一種異常的處理。catch子句用于處理特定類(lèi)型的異常。

例2:

 #include <iostream>
 using namespace std;
 void Test1()
 {
  try
  {
   char* p = new char[0x7fffffff]; //拋出異常
  }
  catch (exception e)
  {
   cout << e.what() << endl; //捕獲異常,然后程序結(jié)束
  }
 }
 int main()
 {
  Test1();
  system("pause");
  return 0;
 }

結(jié)果:

當(dāng)使用new進(jìn)行開(kāi)空間時(shí),申請(qǐng)內(nèi)存失敗,就會(huì)拋出異常,此時(shí)捕獲到異常時(shí),就可告訴使用者是哪里的錯(cuò)誤,便于修改

2. 異常的處理規(guī)則

異常是通過(guò)拋出對(duì)象而引發(fā)的,該對(duì)象的類(lèi)型決定了應(yīng)該激活哪個(gè)處理代碼。

被選中的處理代碼是調(diào)用鏈中與該對(duì)象類(lèi)型匹配且離拋出異常位置最近的那一個(gè)。

拋出異常后會(huì)釋放局部存儲(chǔ)對(duì)象,所以被拋出的對(duì)象也就還給系統(tǒng)了,throw表達(dá)式會(huì)初始化一個(gè)拋出特殊的匿名對(duì)象,異常對(duì)象由編譯管理,異常對(duì)象在傳給對(duì)應(yīng)的catch處理之后撤銷(xiāo)。

例2:

class Exception//異常類(lèi)
{
public:
 Exception(const string& msg, int id)
 {
  _msg = msg;
  _id = id;
 }
 const char* What() const
 {
  return _msg.c_str();
 }
protected:
 string _msg;
 int _id;
};
template<size_t N = 10>
class Array
{
public:
 int& operator[](size_t pos)
 {
  if (pos >= N)
  {
   Exception e("下標(biāo)不合法", 1); //出了這個(gè)作用域,拋出的異常對(duì)象就銷(xiāo)毀了,這時(shí)會(huì)生成一個(gè)匿名對(duì)象先接受這個(gè)對(duì)象,并傳到外層棧幀。
   throw e;
  }
  return a[pos];
 }
protected:
 int a[N];
};
int f()
{
 try
 {
  Array<> a;
  a[11];
 }
 catch (exception& e)
 {
  cout << e.what() << endl; //類(lèi)型不匹配,找離拋出異常位置最近且類(lèi)型匹配的那個(gè)。
 }
 return 0;
}
int main()
{
 try
 {
  f();
 }
 catch (Exception& e)
 {
  cout << e.What() << endl;
 }
 system("pause");
 return 0;
} 

結(jié)果:

f()函數(shù)中捕獲的異常是標(biāo)準(zhǔn)庫(kù)里面的異常,但拋出異常的對(duì)象是自己定義的異常類(lèi),故類(lèi)型不匹配,找離拋出異常最近的且類(lèi)型匹配的Exception

3. 異常處理?xiàng)U归_(kāi)

1.在try的語(yǔ)句塊內(nèi)聲明的變量在外部是不可以訪問(wèn)的,即使是在catch子句內(nèi)也不可以訪問(wèn)?! ?/p>

2.棧展開(kāi)(尋找異常處理(exception handling)代碼)

棧展開(kāi)會(huì)沿著嵌套函數(shù)的調(diào)用鏈不斷查找,知道找到了已拋出的異常匹配的catch子句。如果在最后還是沒(méi)有找到對(duì)應(yīng)的catch子句的話,則退出主函數(shù)后查找過(guò)程終止,程序調(diào)用標(biāo)準(zhǔn)函數(shù)庫(kù)的terminate()函數(shù),終止該程序的執(zhí)行

具體過(guò)程:

當(dāng)一個(gè)exception被拋出的時(shí)候,控制權(quán)會(huì)從函數(shù)調(diào)用中釋放出來(lái),并需找一個(gè)可以處理的catch子句

對(duì)于一個(gè)拋出異常的try區(qū)段,程序會(huì)先檢查與該try區(qū)段關(guān)聯(lián)的catch子句,如果找到了匹配的catch子句,就使用這個(gè)catch子句處理這個(gè)異常。

沒(méi)有找到匹配的catch子句,如果這個(gè)try區(qū)段嵌套在其他try區(qū)段中,則繼續(xù)檢查與外層try匹配的catch子句。如果仍然沒(méi)有找到匹配的catch子句,則退出當(dāng)前這個(gè)主調(diào)函數(shù),并在調(diào)用了剛剛退出的這個(gè)函數(shù)的其他函數(shù)中尋找。

3. catch子句的查找:  

catch子句是按照出現(xiàn)的順序進(jìn)行匹配的(以例2來(lái)說(shuō),異常先會(huì)匹配catch(exception e)子句,然后在匹配 catch (Exception e)子句,一步一步的棧展開(kāi))。在尋找catch子句的過(guò)程中,拋出的異??梢赃M(jìn)行類(lèi)型轉(zhuǎn)換,但是比較嚴(yán)格:

允許從非常量轉(zhuǎn)換到常量的類(lèi)型轉(zhuǎn)換(權(quán)限縮?。?/p>

允許從派生類(lèi)到基類(lèi)的轉(zhuǎn)換。

允許數(shù)組被轉(zhuǎn)換成為指向數(shù)組(元素)類(lèi)型的指針,函數(shù)被轉(zhuǎn)換成指向該函數(shù)類(lèi)型的指針(降級(jí)問(wèn)題)

標(biāo)準(zhǔn)算術(shù)類(lèi)型的轉(zhuǎn)換(比如:把bool型和char型轉(zhuǎn)換成int型)和類(lèi)類(lèi)型轉(zhuǎn)換(使用類(lèi)的類(lèi)型轉(zhuǎn)換運(yùn)算符和轉(zhuǎn)換構(gòu)造函數(shù))。

4. 異常處理中需要注意的問(wèn)題

如果拋出的異常一直沒(méi)有函數(shù)捕獲(catch),則會(huì)一直上傳到c++運(yùn)行系統(tǒng)那里,導(dǎo)致整個(gè)程序的終止

一般在異常拋出后資源可以正常被釋放,但注意如果在類(lèi)的構(gòu)造函數(shù)中拋出異常,系統(tǒng)是不會(huì)調(diào)用它的析構(gòu)函數(shù)的,處理方法是:如果在構(gòu)造函數(shù)中要拋出異常,則在拋出前要記得刪除申請(qǐng)的資源。

異常處理僅僅通過(guò)類(lèi)型而不是通過(guò)值來(lái)匹配的,所以catch塊的參數(shù)可以沒(méi)有參數(shù)名稱,只需要參數(shù)類(lèi)型。

函數(shù)原型中的異常說(shuō)明要與實(shí)現(xiàn)中的異常說(shuō)明一致,否則容易引起異常沖突。

應(yīng)該在throw語(yǔ)句后寫(xiě)上異常對(duì)象時(shí),throw先通過(guò)Copy構(gòu)造函數(shù)構(gòu)造一個(gè)新對(duì)象,再把該新對(duì)象傳遞給 catch.  

注:那么當(dāng)異常拋出后新對(duì)象如何釋放?

異常處理機(jī)制保證:異常拋出的新對(duì)象并非創(chuàng)建在函數(shù)棧上,而是創(chuàng)建在專用的異常棧上,因此它才可以跨接多個(gè)函數(shù)而傳遞到上層,否則在棧清空的過(guò)程中就會(huì)被銷(xiāo)毀。所有從try到throw語(yǔ)句之間構(gòu)造起來(lái)的對(duì)象的析構(gòu)函數(shù)將被自動(dòng)調(diào)用。但如果一直上溯到main函數(shù)后還沒(méi)有找到匹配的catch塊,那么系統(tǒng)調(diào)用terminate()終止整個(gè)程序,這種情況下不能保證所有局部對(duì)象會(huì)被正確地銷(xiāo)毀。

catch塊的參數(shù)推薦采用地址傳遞而不是值傳遞,不僅可以提高效率,還可以利用對(duì)象的多態(tài)性。另外,派生類(lèi)的異常撲獲要放到父類(lèi)異常撲獲的前面,否則,派生類(lèi)的異常無(wú)法被撲獲。

編寫(xiě)異常說(shuō)明時(shí),要確保派生類(lèi)成員函數(shù)的異常說(shuō)明和基類(lèi)成員函數(shù)的異常說(shuō)明一致,即派生類(lèi)改寫(xiě)的虛函數(shù)的異常說(shuō)明至少要和對(duì)應(yīng)的基類(lèi)虛函數(shù)的異常說(shuō)明相同,甚至更加嚴(yán)格,更特殊。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。

相關(guān)文章

  • C語(yǔ)言算法練習(xí)之?dāng)?shù)組元素排序

    C語(yǔ)言算法練習(xí)之?dāng)?shù)組元素排序

    這篇文章主要為大家介紹了C語(yǔ)言算法練習(xí)中數(shù)組元素排序的實(shí)現(xiàn)方法,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C語(yǔ)言有一定幫助,需要的可以參考一下
    2022-09-09
  • C++ OpenCV實(shí)現(xiàn)圖像去水印功能

    C++ OpenCV實(shí)現(xiàn)圖像去水印功能

    本文將介紹如何使用OpenCV C++ 進(jìn)行簡(jiǎn)單圖像水印去除。我們?cè)诰W(wǎng)上download圖片時(shí),經(jīng)常因?yàn)榘鏅?quán)問(wèn)題有水印。本案例通過(guò)編寫(xiě)算法進(jìn)行簡(jiǎn)單水印去除。需要的可以參考一下
    2022-01-01
  • C++利用GPAC實(shí)現(xiàn)生成MP4文件的示例代碼

    C++利用GPAC實(shí)現(xiàn)生成MP4文件的示例代碼

    GPAC主要針對(duì)學(xué)生和內(nèi)容創(chuàng)作者,代表了一個(gè)跨平臺(tái)的多媒體框架,開(kāi)發(fā)人員可以使用它在?LGPL?許可下制作開(kāi)源媒體。本文就來(lái)用GPAC實(shí)現(xiàn)生成MP4文件,感興趣的可以了解一下
    2023-02-02
  • C++中二進(jìn)制數(shù)據(jù)序列化和反序列化詳解

    C++中二進(jìn)制數(shù)據(jù)序列化和反序列化詳解

    這篇文章主要為大家詳細(xì)介紹了C++中二進(jìn)制數(shù)據(jù)序列化和反序列化的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以了解下
    2023-11-11
  • 用C語(yǔ)言實(shí)現(xiàn)從文本文件中讀取數(shù)據(jù)后進(jìn)行排序的功能

    用C語(yǔ)言實(shí)現(xiàn)從文本文件中讀取數(shù)據(jù)后進(jìn)行排序的功能

    這是一個(gè)十分可靠的程序,這個(gè)程序的查錯(cuò)能力非常強(qiáng)悍。程序包含了文件操作,歸并排序和字符串輸入等多種技術(shù)。對(duì)大家學(xué)習(xí)C語(yǔ)言很有幫助,有需要的一起來(lái)看看。
    2016-08-08
  • C++私有繼承與EBO深入分析講解

    C++私有繼承與EBO深入分析講解

    這篇文章主要介紹了C++私有繼承,在私有繼承當(dāng)中,基類(lèi)的公有成員和保護(hù)成員都會(huì)成為派生類(lèi)的私有成員。這意味著基類(lèi)的方法都會(huì)被private關(guān)鍵字描述,我們可以在派生類(lèi)中使用它,但類(lèi)對(duì)象無(wú)法直接調(diào)用,下面來(lái)看看詳細(xì)內(nèi)容吧
    2022-08-08
  • C/C++中宏/Macro的深入講解

    C/C++中宏/Macro的深入講解

    這篇文章主要給大家介紹了關(guān)于C/C++中宏/Macro的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用C/C++具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • visual studio 2015下boost庫(kù)配置教程

    visual studio 2015下boost庫(kù)配置教程

    這篇文章主要為大家詳細(xì)介紹了visual studio 2015下boost庫(kù)的配置教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • Qt為exe添加ico圖片的簡(jiǎn)單實(shí)現(xiàn)步驟

    Qt為exe添加ico圖片的簡(jiǎn)單實(shí)現(xiàn)步驟

    這篇文章主要給大家介紹了關(guān)于Qt為exe添加ico圖片的簡(jiǎn)單實(shí)現(xiàn)步驟,通過(guò)文中介紹的方法可以幫助大家實(shí)現(xiàn)這個(gè)自定義exe圖標(biāo)的效果,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2022-07-07
  • C++中如何實(shí)現(xiàn)回調(diào)的方法示例

    C++中如何實(shí)現(xiàn)回調(diào)的方法示例

    這篇文章主要給大家介紹了關(guān)于C++中如何實(shí)現(xiàn)回調(diào)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用c++具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-10-10

最新評(píng)論

喀喇| 洪洞县| 雷山县| 东乡| 永清县| 乐山市| 陵水| 石狮市| 伊金霍洛旗| 珠海市| 揭东县| 清丰县| 通化县| 景东| 南郑县| 襄汾县| 南部县| 梁山县| 长兴县| 海晏县| 岚皋县| 嘉鱼县| 梁河县| 武邑县| 石首市| 韶山市| 蚌埠市| 金塔县| 达拉特旗| 鹿泉市| 奇台县| 阿拉尔市| 瑞安市| 吉安县| 慈溪市| 高州市| 贵州省| 德江县| 黎平县| 卢湾区| 吉安县|