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

首頁 > 學院 > 開發設計 > 正文

C++箴言:防止異常離開析構函數

2019-11-17 05:09:58
字體:
來源:轉載
供稿:網友

  C++ 并不禁止從析構函數中引發異常,但是這確實妨礙了實踐。至于有什么好的理由,考慮:

  

  class Widget {

   public:

    ...

    ~Widget() { ... } // assume this might emit an exception

  };

  

  void doSomething()

  {

   std::vector v;

   ...

  } // v is automatically destroyed here

  當 vector v 被析構時,它有責任銷毀它包含的所有 Widgets。假設 v 中有十個 Widgets,在銷毀第一個的時候,拋出一個異常。其他 9個 Widgets 仍然必須被銷毀(否則他們持有的任何資源將被泄漏),所以 v 應該調用它們的析構函數。但是假設在這個調用期間,第二個 Widgets 的析構函數又拋出一個異常。現在有兩個異常同時在活動中,對于 C++ 來說這太多了。在非常巧合的條件下發生這樣兩個同時活動的異常,程序的執行會終止或者引發未定義行為。在本例中,將引發未定義行為。與此相同,使用任何標準庫容器(比如,list,set),任何 TR1中的容器,甚至是一個數組,都可能會引發未定義問題。并非必須是容器或數組才會陷入麻煩。程序夭折或未定義行為是析構函數引發異常的結果,即使沒有使用容器或數組也會如此。C++ 不喜歡引發異常的析構函數。 這比較輕易理解,但是假如你的析構函數需要執行一個可能失敗而拋出異常的操作,該怎么辦呢?例如,假設你與一個數據庫連接類一起工作:

  

  class DBConnection {

   public:

    ...

   

    static DBConnection create(); // function to return

    // DBConnection objects; params

    // omitted for simplicity

  void close(); // close connection; throw an

  }; // exception if closing fails

   更多文章 更多內容請看C/C++技術專題專題,或
  為了確保客戶不會忘記調用 DBconnection 對象的 close,一個合理的主意是為 DBConnection 建立一個資源治理類,在它的析構函數中調用 close。這樣的資源治理類將在以后的文章中探討,但在這里,只要認為這樣一個類的析構函數看起來像這樣就足夠了:

  

  class DBConn { // class to manage DBConnection

   public: // objects

    ...

    ~DBConn() // make sure database connections

    { // are always closed

     db.close();

    }

   PRivate:

    DBConnection db;

  };

  它答應客戶像這樣編程:

  

  {

   // open a block

   DBConn dbc(DBConnection::create()); // create DBConnection object

   // and turn it over to a DBConn

   // object to manage

   ... // use the DBConnection object

   // via the DBConn interface

  } // at end of block, the DBConn

  // object is destroyed, thus

  // automatically calling close on

  // the DBConnection object

  既然能成功地調用 close 那就好了,但是假如這個調用導致了異常,DBConn 的析構函數將散播那個異常,也就是說,它將離開析構函數。這就產生了問題,因為析構函數拋出了一個燙手的山芋。 更多文章 更多內容請看C/C++技術專題專題,或
  有兩個主要的方法避免這個麻煩。DBConn 的析構函數能:

  終止程序 假如 close 拋出異常,調用 abort。

  

  DBConn::~DBConn()

  {

   try { db.close(); }

   catch (...) {


    make log entry that the call to close failed;

    std::abort();

   }

  }

  假如程序在析構過程遭碰到錯誤后不能繼續運行,這就是一個合理的選擇。它有一個好處是:假如答應從析構函數散播異常可能會引起未定義行為,這樣就能防止它發生。也就是說,調用 abort 就預先防止了未定義行為。

  抑制這個異常 起因于調用 close:

  

  DBConn::~DBConn()

  {

   try { db.close(); }

   catch (...) {

    make log entry that the call to close failed;

   }

  }

  通常,抑制異常是一個不好的主意,因為它會隱瞞重要的信息——某些事情失敗了!可是,有些時候,抑制異常比冒程序夭折或未定義行為的風險更可取。程序必須能夠在遭碰到錯誤并忽略之后還能繼續可靠地執行,這才能成為一個可行的選擇。

  這些方法都不太吸引人。它們的問題在于程序無法在第一現場對引起 close 拋出異常的條件做出回應。

  一個更好的策略是設計 DBConn 的接口,以使它的客戶有機會對可能會發生的問題做出回應。例如,DBConn 能夠自己提供一個 close 函數,從而給客戶一個機會去處理從那個操作中發出的異常。它還能保持對它的 DBConnection 是否已被關閉的跟蹤,假如沒有關閉就在析構函數中自己關閉它。這樣可以防止連接被泄漏。假如在 DBConnection 的析構函數中調用 close 失敗,無論如何,我們還可以再返回到終止或者抑制。

  

  class DBConn {

  public:

  ...

  

  void close() // new function for

  {

   // client use

   db.close();

   closed = true;

  }

  

  ~DBConn()

  {

   if (!closed) {

    try { // close the connection

     db.close(); // if the client didn’t

    }

    catch (...) { // if closing fails,

     make log entry that call to close failed; // note that and

     ... // terminate or swallow

    }

   }

  

   private:

    DBConnection db;

    bool closed;

  };

  將調用 close 的責任從 DBConn 的析構函數轉移到 DBConn 的客戶(同時在 DBConn 的析構函數中包含一個“候補”調用)可能會作為一種肆無忌憚地推卸責任的做法而刺激你。你甚至可以把它看作一個忠告(使接口易于正確使用)的違反。實際上,這都不正確。假如一個操作可能失敗而拋出一個異常,而且可能是一個需要處理的異常,這個異常就必須來自非析構函數。這是因為析構函數引發異常是危險的,永遠都要冒著程序夭折或未定義行為的風險。在此例中,讓客戶調用 close 并不是強加給他們的負擔,而是給他們一個時機去應付錯誤,否則他們將沒有機會做出回應。假如他們找不到可用到機會(或許因為他們相信不會有錯誤真的發生),他們可能忽略它,依靠 DBConn 的析構函數為他們調用 close。假如一個錯誤恰恰發生在那時——假如由 close 拋出——假如 DBConn 抑制了那個異常或者終止了程序,他們將無處訴苦。究竟,他們無處著手處理問題,他們將不再使用它。

  Things to Remember

  ·析構函數應該永不引發異常。假如析構函數調用了可能拋出異常的函數,析構函數應該捕捉任何異常,然后抑制它們或者終止程序。

  ·假如類客戶需要能對一個操作拋出的異常做出回應,則那個類應該提供一個常規的(非析構函數)函數來完成這個操作。 更多文章 更多內容請看C/C++技術專題專題,或

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 文山县| 安泽县| 宜州市| 桐梓县| 仁寿县| 景洪市| 永仁县| 祁东县| 南川市| 汤阴县| 驻马店市| 南漳县| 呼伦贝尔市| 临湘市| 通道| 泸定县| 万州区| 万荣县| 安仁县| 中卫市| 虹口区| 苍南县| 南涧| 汕头市| 禄劝| 临洮县| 侯马市| 巴马| 六枝特区| 灵寿县| 普兰店市| 铜山县| 文化| 民勤县| 库车县| 连州市| 肥乡县| 湖南省| 洛南县| 方正县| 防城港市|