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

字號:

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