<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                # Item 8: 防止因為 exceptions(異常)而離開 destructors(析構函數) 作者:Scott Meyers 譯者:fatalerror99 (iTePub's Nirvana) 發布:http://blog.csdn.net/fatalerror99/ C++ 并不禁止從 destructors(析構函數)中引發 exceptions(異常),但是它堅決地阻止這樣的實踐。至于有什么好的理由,考慮: ``` class Widget { public: ... ~Widget() { ... } // assume this might emit an exception }; void doSomething() { std::vector<Widget> v; ... } // v is automatically destroyed here ``` 當 vector v 被析構時,它有責任析構它包含的所有 Widgets。假設 v 中有十個 Widgets,在第一個的析構過程中,拋出一個 exception(異常)。其它 9 個 Widgets 仍然必須被析構(否則它們持有的所有資源將被泄漏),所以 v 應該調用它們的 destructors(析構函數)。但是假設在這個調用期間,第二個 Widget 的 destructors(析構函數)又拋出一個 exception(異常)。現在同時有兩個活動的 exceptions(異常),對于 C++ 來說,這太多了。在非常巧合的條件下產生這樣兩個同時活動的異常,程序的執行會終止或者引發 undefined behavior(未定義行為)。在本例中,將引發 undefined behavior(未定義行為)。使用任何其它的標準庫 container(容器)(比如,list,set),任何 TR1(參見 Item 54)中的 container(容器),甚至是一個 array(數組),都可能會引發同樣的 undefined behavior(未定義行為)。也并非必須是 containers(容器)或 arrays(數組)才會陷入麻煩。程序過早終止或 undefined behavior(未定義行為)是 destructors(析構函數)引發 exceptions(異常)的結果,即使沒有使用 containers(容器)和 arrays(數組)也會如此。C++ 不喜歡引發 exceptions(異常)的 destructors(析構函數)。 這比較容易理解,但是如果你的 destructor(析構函數)需要執行一個可能失敗而拋出一個 exception(異常)的操作,該怎么辦呢?例如,假設你與一個數據庫連接類一起工作: ``` 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 ``` 為了確保客戶不會忘記在 DBconnection objects(對象)上調用 close,一個合理的主意是為 DBConnection 建立一個 resource-managing class(資源管理類),在它的 destructor(析構函數)中調用 close。這樣的 resource-managing classes(資源管理類)將在 Chapter 3(第三章)中一探究竟,但在這里,只要認為這樣一個 class(類)的 destructor(析構函數)看起來像這樣就足夠了: ``` 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 就可以了,但是如果這個調用導致一個 exception(異常),DBConn 的 destructor(析構函數)將傳播那個 exception(異常),也就是說,它將離開 destructor(析構函數)。這就產生了問題,因為 destructor(析構函數)拋出了一個燙手的山芋。 有兩個主要的方法避免這個麻煩。DBConn 的 destructor(析構函數)能: * Terminate the program if close tHRows(如果 close 拋出異常就終止程序),一般是通過調用 abort: ``` DBConn::~DBConn() { try { db.close(); } catch (...) { make log entry that the call to close failed; std::abort(); } } ``` 如果在析構的過程遭遇到錯誤后程序不能繼續運行,這就是一個合理的選擇。它有一個好處是:如果允許從 destructor(析構函數)傳播 exception(異常)可能會導致 undefined behavior(未定義行為),這樣就能防止它發生。也就是說,調用 abort 就可以預先防止 undefined behavior(未定義行為)。 * Swallow the exception arising from the call to close(抑制這個對 close 的調用造成的異常): ``` DBConn::~DBConn() { try { db.close(); } catch (...) { make log entry that the call to close failed; } } ``` 通常,swallowing exceptions(抑制異常)是一個不好的主意,因為它會隱瞞重要的信息—— something failed(某事失敗了)!然而,有些時候,swallowing exceptions(抑制異常)比冒程序過早終止或 undefined behavior(未定義行為)的風險更可取。程序必須能夠在遭遇到一個錯誤并忽略之后還能繼續可靠地運行,這才能成為一個可行的選擇。 這些方法都不太吸引人。它們的問題首先在于程序無法對引起 close 拋出 exception(異常)的條件做出回應。 一個更好的策略是設計 DBConn 的 interface(接口),以使它的客戶有機會對可能會發生的問題做出回應。例如,DBConn 能夠自己提供一個 close 函數,從而給客戶一個機會去處理從那個操作中發生的 exception(異常)。它還能保持對它的 DBConnection 是否已被 closed 的跟蹤,如果沒有就在 destructor(析構函數)中自己關閉它。這樣可以防止連接被泄漏。如果在 DBConnection(原文如此,嚴重懷疑此處應為 DBConn ——譯者注)的 destructor(析構函數)中對 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 的 destructor(析構函數)移交給 DBConn 的客戶(同時在 DBConn 的 destructor(析構函數)中包含一個“候補”調用)可能會作為一種肆無忌憚地推卸責任的做法而使你吃驚。你甚至可以把它看作對 Item 18 中關于使 interfaces(接口)易于正確使用的建議的違背。實際上,這都不正確。如果一個操作可能失敗而拋出一個 exception(異常),而且可能有必要處理這個 exception(異常),這個 exception(異常)就 has to come from some non-destructor function(必須來自非析構函數)。這是因為 destructor(析構函數)引發 exception(異常)是危險的,永遠都要冒著程序過早終止或 undefined behavior(未定義行為)的風險。在本例中,讓客戶自己調用 close 并不是強加給他們的負擔,而是給他們一個時機去應付錯誤,否則他們將沒有機會做出回應。如果他們找不到可用到機會(或許因為他們相信不會有錯誤真的發生),他們可以忽略它,依靠 DBConn 的 destructor(析構函數)為他們調用 close。如果一個錯誤恰恰在那時發生——如果由 close 拋出——如果 DBConn 抑制了那個 exception(異常)或者終止了程序,他們將無處訴苦。畢竟,他們無處著手處理問題,他們將不再使用它。 Things to Remember * destructor(析構函數)應該永不引發 exceptions(異常)。如果 destructor(析構函數)調用了可能拋出異常的函數,destructor(析構函數)應該捕捉所有異常,然后抑制它們或者終止程序。 * 如果 class(類)客戶需要能對一個操作拋出的 exceptions(異常)做出回應,則那個 class(類)應該提供一個常規的函數(也就是說,non-destructor(非析構函數))來完成這個操作。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看