計(jì)算機(jī)二級(jí)C++輔導(dǎo):別讓異常逃離析構(gòu)函數(shù)

字號(hào):

這節(jié)和異常有關(guān),這一塊是我不太熟悉的,只能先把自己理解的記錄下來(lái)。
    1 class Widget
    2 {
    3 public:
    4
    5   ~Widget() {} //假設(shè)這里會(huì)吐出一個(gè)異常
    6 };
    7
    8 void doSomething()
    9 {
    10   std::vector v;
    11
    12 }//v在這里自動(dòng)銷(xiāo)毀
    上面的代碼中,假設(shè)v含有10個(gè)Widget,如果在前面幾個(gè)的析構(gòu)函數(shù)中彈出異常,則程序會(huì)過(guò)早結(jié)束或者出現(xiàn)不明確行為。
    確實(shí)不鼓勵(lì)在析構(gòu)函數(shù)中拋出異常,可是如果程序在析構(gòu)函數(shù)中必須執(zhí)行一個(gè)動(dòng)作,加入收藏而該動(dòng)作可能會(huì)在失敗時(shí)拋出異常,該怎么辦呢?比如下例:
    1 class DBConnection
    2 {
    3 public:
    4   static DBConnection create();
    5   void close();//關(guān)閉連接,失敗則拋出異常
    6 };
    為了確保用戶(hù)不忘記調(diào)用close()關(guān)閉連接,我們可以創(chuàng)建一個(gè)管理DBConnection資源的類(lèi):
    1 class DBConn
    2 {
    3 public:
    4   ~DBConn()
    5   {
    6     db.close();
    7   }
    8 private:
    9   DBConnection db;
    10 };
    這樣在使用時(shí),如果close沒(méi)有異常,則會(huì)很完美,不然DBConn就會(huì)使得它離開(kāi)close函數(shù),這會(huì)出現(xiàn)上述問(wèn)題。
    我們可以在DBConn的析構(gòu)函數(shù)中,自己提前處理這個(gè)異常,但是這么做對(duì)于“導(dǎo)致close拋出異?!钡那闆r無(wú)法做出反應(yīng)。
    一個(gè)比較好的策略是重新定義DBConn接口,給用戶(hù)一個(gè)機(jī)會(huì)自己處理這種異常,比如,給用戶(hù)定義一個(gè)函數(shù)close:
    1 class DBConn
    2 {
    3 public:
    4   void close()//讓用戶(hù)有機(jī)會(huì)自己捕捉異常
    5   {
    6     db.close();
    7     closed = true;
    8   }
    9
    10   ~DBConn()
    11   {
    12     if(!closed)
    13     {
    14       try{
    15         db.close();
    16       }
    17       catch(){
    18         //記錄下對(duì)close的調(diào)用失敗
    19       }
    20   }
    21 private:
    22   DBConnection db;
    23   bool closed;
    24 };
    這樣一來(lái),就有了雙保險(xiǎn),用戶(hù)可以自己處理異常,如果他們不處理,則析構(gòu)函數(shù)會(huì)自動(dòng)吞下異常。
    總結(jié):
    1.在析構(gòu)函數(shù)中盡可能不要吐出異常,如果真要吐出就在析構(gòu)函數(shù)中捕獲所以的異常,并提前結(jié)束程序或吞下它們;
    2.如果用戶(hù)需要自己處理異常,則在類(lèi)中應(yīng)該提供一個(gè)普通函數(shù)處理。