国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

C++中禁止異常信息傳遞到析構(gòu)函數(shù)外

2019-11-17 05:38:51
字體:
供稿:網(wǎng)友

  在有兩種情況下會(huì)調(diào)用析構(gòu)函數(shù)。第一種是在正常情況下刪除一個(gè)對(duì)象,例如對(duì)象超出了作用域或被顯式地delete。第二種是異常傳遞的堆棧輾轉(zhuǎn)開解(stack-unwinding)過程中,由異常處理系統(tǒng)刪除一個(gè)對(duì)象。

  在上述兩種情況下,調(diào)用析構(gòu)函數(shù)時(shí)異常可能處于激活狀態(tài)也可能沒有處于激活狀態(tài)。遺憾的是沒有辦法在析構(gòu)函數(shù)內(nèi)部區(qū)分出這兩種情況。因此在寫析構(gòu)函數(shù)時(shí)你必須保守地假設(shè)有異常被激活,因?yàn)榧偃缭谝粋€(gè)異常被激活的同時(shí),析構(gòu)函數(shù)也拋出異常,并導(dǎo)致程序控制權(quán)轉(zhuǎn)移到析構(gòu)函數(shù)外,C++將調(diào)用terminate函數(shù)。這個(gè)函數(shù)的作用正如其名字所表示的:它終止你程序的運(yùn)行,而且是立即終止,甚至連局部對(duì)象都沒有被釋放。

  下面舉一個(gè)例子,一個(gè)session類用來跟蹤在線計(jì)算機(jī)的sessions,session就是運(yùn)行在從你一登錄計(jì)算機(jī)開始一直到注銷出系統(tǒng)為止的這段期間的某種東西。每個(gè)Session對(duì)象關(guān)注的是它建立與釋放的日期與時(shí)間:

class Session {
public:
 Session();
 ~Session();
 ...
PRivate:
 static void logCreation(Session *objAddr);
 static void logDestrUCtion(Session *objAddr);
};
  函數(shù)logCreation 和 logDestruction被分別用于記錄對(duì)象的建立與釋放。我們因此可以這樣編寫Session的析構(gòu)函數(shù):

Session::~Session()
{
 logDestruction(this);
}
  一切看上去很好,但是假如logDestruction拋出一個(gè)異常,會(huì)發(fā)生什么事呢?異常沒有被Session的析構(gòu)函數(shù)捕捉住,所以它被傳遞到析構(gòu)函數(shù)的調(diào)用者那里。但是假如析構(gòu)函數(shù)本身的調(diào)用就是源自于某些其它異常的拋出,那么terminate函數(shù)將被自動(dòng)調(diào)用,徹底終止你的程序。這不是你所希望發(fā)生的事情。程序沒有記錄下釋放對(duì)象的信息,這是不幸的,甚至是一個(gè)大麻煩。那么事態(tài)果真嚴(yán)重到了必須終止程序運(yùn)行的地步了么?假如沒有,你必須防止在logDestruction內(nèi)拋出的異常傳遞到Session析構(gòu)函數(shù)的外面。唯一的方法是用try和catch blocks。一種很自然的做法會(huì)這樣編寫函數(shù):

Session::~Session()
{
 try {
  logDestruction(this);
 }
 catch (...) {
  cerr << "Unable to log destruction of Session object "
   << "at address "
   << this
   << "./n";
 }
}
  但是這樣做并不比你原來的代碼安全。假如在catch中調(diào)用Operator<<時(shí)導(dǎo)致一個(gè)異常被拋出,我們就又碰到了老問題,一個(gè)異常被轉(zhuǎn)遞到Session析構(gòu)函數(shù)的外面。

  我們可以在catch中放入try,但是這總得有一個(gè)限度,否則會(huì)陷入循環(huán)。因此我們?cè)卺尫臩ession時(shí)必須忽略掉所有它拋出的異常:

Session::~Session()
{
 try {
  logDestruction(this);
 }
 catch (...) { }
}
  catch表面上似乎沒有做任何事情,這是一個(gè)假象,實(shí)際上它阻止了任何從logDestruction拋出的異常被傳遞到session析構(gòu)函數(shù)的外面。我們現(xiàn)在能高枕無憂了,無論session對(duì)象是不是在堆棧輾轉(zhuǎn)開解(stack unwinding)中被釋放,terminate函數(shù)都不會(huì)被調(diào)用。

  不答應(yīng)異常傳遞到析構(gòu)函數(shù)外面還有第二個(gè)原因。假如一個(gè)異常被析構(gòu)函數(shù)拋出而沒有在函數(shù)內(nèi)部捕捉住,那么析構(gòu)函數(shù)就不會(huì)完全運(yùn)行(它會(huì)停在拋出異常的那個(gè)地方上)。假如析構(gòu)函數(shù)不完全運(yùn)行,它就無法完成希望它做的所有事情。例如,我們對(duì)session類做一個(gè)修改,在建立session時(shí)啟動(dòng)一個(gè)數(shù)據(jù)庫事務(wù)(database transaction),終止session時(shí)結(jié)束這個(gè)事務(wù):

Session::Session() // 為了簡單起見,,
{ // 這個(gè)構(gòu)造函數(shù)沒有
 // 處理異常
 logCreation(this);
 startTransaction(); // 啟動(dòng) database transaction
}

Session::~Session()
{
 logDestruction(this);
 endTransaction(); // 結(jié)束database transaction
}
  假如在這里logDestruction拋出一個(gè)異常,在session構(gòu)造函數(shù)內(nèi)啟動(dòng)的transaction就沒有被終止。我們也許能夠通過重新調(diào)整session析構(gòu)函數(shù)內(nèi)的函數(shù)調(diào)用順序來消除問題,但是假如endTransaction也拋出一個(gè)異常,我們除了回到使用try和catch外,別無選擇。

  綜上所述,我們知道禁止異常傳遞到析構(gòu)函數(shù)外有兩個(gè)原因,第一能夠在異常轉(zhuǎn)遞的堆棧輾轉(zhuǎn)開解(stack-unwinding)的過程中,防止terminate被調(diào)用。第二它能幫助確保析構(gòu)函數(shù)總能完成我們希望它做的所有事情。(假如你仍然不很信服我所說的理由,可以去看Herb Sutter的文章Exception-Safe Generic Containers ,非凡是“Destructors That Throw and Why They’re Evil”這段)。

上一篇:C 編程最佳實(shí)踐

下一篇:S-DES

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 广元市| 天津市| 始兴县| 辛集市| 固始县| 沅陵县| 岢岚县| 红河县| 多伦县| 徐闻县| 惠水县| 五家渠市| 遵化市| 资源县| 景洪市| 衡阳县| 南乐县| 常山县| 浦东新区| 泸西县| 咸阳市| 遂溪县| 澎湖县| 浪卡子县| 资源县| 碌曲县| 若羌县| 崇文区| 兴和县| 蒙城县| 莱芜市| 灵山县| 浙江省| 新巴尔虎左旗| 水富县| 成都市| 海伦市| 南丹县| 华坪县| 宜城市| 景泰县|