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

首頁(yè) > 編程 > C++ > 正文

Effective C++ 條款08:別讓異常逃離析構(gòu)函數(shù)

2019-11-08 19:58:13
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

1.別讓異常逃離析構(gòu)函數(shù)的原因

《Effective C++》第三版中條款08建議不要在析構(gòu)函數(shù)中拋出異常,原因是C++異常機(jī)制不能同時(shí)處理兩個(gè)或兩個(gè)以上的異常。多個(gè)異常同時(shí)存在的情況下,程序若不結(jié)束,會(huì)導(dǎo)致不明確行為。如下代碼:

class Widget{public: ~Widget(){...} //假設(shè)這個(gè)可能吐出一個(gè)異常};void dosomething(){ vector<Widget> v;} //v在這里被自動(dòng)銷(xiāo)毀

函數(shù)dosomething運(yùn)行結(jié)束后,最為棧對(duì)象的vector v將被銷(xiāo)毀,它同時(shí)也有責(zé)任銷(xiāo)毀其內(nèi)含的所有Widgets。假設(shè)v內(nèi)含十個(gè)Widgets,而在析構(gòu)第一個(gè)元素期間,有個(gè)異常被拋出。其他九個(gè)widgets還是應(yīng)該被銷(xiāo)毀(否則他們保存的任何資源都會(huì)發(fā)生泄漏),因此v應(yīng)該調(diào)用它們各個(gè)析構(gòu)函數(shù)。但假設(shè)在那些調(diào)用期間,第二個(gè)widget析構(gòu)函數(shù)又拋出異常,這就出現(xiàn)了上面說(shuō)的情況,多個(gè)異常同時(shí)存在的情況下,程序若不結(jié)束,會(huì)導(dǎo)致不明確行為。

2.解決辦法

如果析構(gòu)函數(shù)必須執(zhí)行一個(gè)動(dòng)作,而該動(dòng)作可能會(huì)在失敗時(shí)拋出異常,該怎么辦?舉個(gè)例子,假設(shè)你使用一個(gè)class負(fù)責(zé)數(shù)據(jù)庫(kù)連接:

class DBConnection { public:   ...   static DBConnection create(); //返回DBConnection對(duì)象;為求簡(jiǎn)化暫略參數(shù)   void close(); //關(guān)閉聯(lián)機(jī);失敗則拋出異常。};

為確保客戶不忘記在DBConnection對(duì)象身上調(diào)用close(),一個(gè)合理的想法是創(chuàng)建一個(gè)用來(lái)管理DBConection資源的class,并在其析構(gòu)函數(shù)中調(diào)用close。這就是著名的以以對(duì)象管理資源

class DBConn { //這個(gè)class用來(lái)管理DBConnection對(duì)象 public:   ...  DBConn(const DBConnection& db){ this->db=db; }  ~DBConn() //確保數(shù)據(jù)庫(kù)連接總是會(huì)被關(guān)閉  {   db.close();  }  PRivate:   DBConnection db;};

調(diào)用close成功,一切都美好。但如果該調(diào)用導(dǎo)致異常,DBConn析構(gòu)函數(shù)會(huì)傳播該異常,也就是允許它離開(kāi)這個(gè)析構(gòu)函數(shù)。那會(huì)造成問(wèn)題,解決辦法如下: (1)方法一:結(jié)束程序 如果close拋出異常就結(jié)束程序,通常調(diào)用abort完成:

DBConn::~DBconn(){ try { db.close(); } catch(...){ abort(); }}

如果程序遭遇一個(gè)“于析構(gòu)期間發(fā)生的錯(cuò)誤”后無(wú)法繼續(xù)執(zhí)行,“強(qiáng)制結(jié)束程序”是個(gè)合理選項(xiàng),畢竟它可以阻止異常從析構(gòu)函數(shù)傳播出去(那會(huì)導(dǎo)致不明確的行為)。也就是說(shuō)調(diào)用abort可以搶先制“不明確行為”于死地。

(2)方法二:吞下因調(diào)用close而發(fā)生的異常

DBConn::~DBConn{ try{ db.close(); } catch(...) { //制作運(yùn)轉(zhuǎn)記錄,記下對(duì)close的調(diào)用失敗! }}

一般而言,將異常吞掉是個(gè)壞主意,因?yàn)樗鼔褐屏恕澳承﹦?dòng)作失敗”的重要信息!然而有時(shí)候吞下異常也比負(fù)擔(dān)“草率結(jié)束程序”或“不明確行為帶來(lái)的風(fēng)險(xiǎn)”好。為了讓這成為一個(gè)可行方案,程序必須能夠繼續(xù)可靠的執(zhí)行。

(3)方法三:重新設(shè)計(jì)DBConn接口,使其客戶有機(jī)會(huì)對(duì)可能出現(xiàn)的異常作出反應(yīng) 我們可以給DBConn添加一個(gè)close函數(shù),賦予客戶一個(gè)機(jī)會(huì)可以處理“因該操作而發(fā)生的異常”。把調(diào)用close的責(zé)任從DBConn析構(gòu)函數(shù)手上移到DBConn客戶手中,你也許會(huì)認(rèn)為它違反了“讓接口容易被正確使用”的忠告。實(shí)際上這污名并不成立。如果某個(gè)操作可能在失敗的時(shí)候拋出異常,而又存在某種需要必須處理該異常,那么這個(gè)異常必須來(lái)自析構(gòu)函數(shù)以外的某個(gè)函數(shù)。因?yàn)槲鰳?gòu)函數(shù)吐出異常就是危險(xiǎn),總會(huì)帶來(lái)“過(guò)早結(jié)束程序”或“發(fā)生不明確行為”的風(fēng)險(xiǎn)。

class DBConn {public: ... void close() //供客戶使用的新函數(shù) { db.close(); closed = true; } ~DBConn(){ if(!closed) { try { //關(guān)閉連接(如果客戶不調(diào)用DBConn::close) db.close(); } catch(...) { //如果關(guān)閉動(dòng)作失敗,記錄下來(lái)并結(jié)束程序或吞下異常。 制作運(yùn)轉(zhuǎn)記錄,記下對(duì)close的調(diào)用失敗; ... } } }private: DBConnection db; bool closed;};

本例要說(shuō)的是,由客戶自己調(diào)用close并不會(huì)對(duì)他們帶來(lái)負(fù)擔(dān),而是給他們一個(gè)處理錯(cuò)誤的機(jī)會(huì)。如果他們不認(rèn)為這個(gè)機(jī)會(huì)有用(或許他們堅(jiān)信不會(huì)有錯(cuò)誤發(fā)生),可能忽略它,依賴DBConn析構(gòu)函數(shù)去調(diào)用close。

請(qǐng)記住: (1)析構(gòu)函數(shù)絕對(duì)不要吐出異常,如果一個(gè)被析構(gòu)函數(shù)調(diào)用的函數(shù)可能拋出異常,析構(gòu)函數(shù)應(yīng)該捕捉任何異常,然后吞下它們(不傳播)或結(jié)束程序。 (2)如果客戶需要對(duì)某個(gè)操作函數(shù)運(yùn)行期間拋出的異常作出反應(yīng),那么class應(yīng)該提供一個(gè)普通函數(shù)(而非在析構(gòu)函數(shù)中)執(zhí)行該操作。


參考文獻(xiàn)

[1]Effective c++學(xué)習(xí)筆記——條款08:別讓異常逃離析構(gòu)函數(shù)


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表

圖片精選

主站蜘蛛池模板: 长葛市| 灌云县| 舞阳县| 连州市| 县级市| 温州市| 广宗县| 广水市| 崇文区| 辽阳市| 牡丹江市| 鹰潭市| 岐山县| 万山特区| 韶山市| 兴国县| 闽清县| 密山市| 昆明市| 长岭县| 佛山市| 乌拉特后旗| 建宁县| 宜都市| 汉阴县| 宝清县| 白山市| 濉溪县| 论坛| 福建省| 翁源县| 莱州市| 东安县| 临武县| 漳浦县| 建始县| 旌德县| 朔州市| 南京市| 门源| 蓬安县|