<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          關(guān)于C++異常,你必須知道的

          本文是作者翻譯過(guò)C++之父Bjarne Stroustrup的技術(shù)文章C++核心準(zhǔn)則中有關(guān)C++中異常的文章之后的總結(jié),希望讀者通過(guò)本文可以對(duì)C++異常有一個(gè)全面,快速的了解:


          異常處理機(jī)制希望解決的問(wèn)題

          為了使用錯(cuò)誤處理系統(tǒng)化,健壯和不繁瑣。例如下面的代碼:

          void f2(int i)   // Clumsy and error-prone: explicit release
          {
          int* p = new int[12];
          // ...
          if (i < 17) {
          delete[] p;
          throw Bad{"in f()", i};
          }
          // ...
          }

          代碼中的作者需要針對(duì)每種錯(cuò)誤進(jìn)行處理,更為復(fù)雜的是當(dāng)程序的規(guī)模達(dá)到一定程度之后,在各個(gè)模塊之間和調(diào)用的各個(gè)層級(jí)之間傳遞錯(cuò)誤信息也會(huì)變成一個(gè)巨大的負(fù)擔(dān)。異常就是為了解決這個(gè)問(wèn)題而出現(xiàn)的。


          推薦使用異常的情況

          一般情況下會(huì)認(rèn)為異常意味著重大的例外事件和錯(cuò)誤。例如下面的情況:

          • 一個(gè)前提條件沒(méi)有滿(mǎn)足

          • 構(gòu)造函數(shù)無(wú)法構(gòu)造對(duì)象(無(wú)法建立類(lèi)的不變式)

          • 越界錯(cuò)誤(例如 v[v.size()]=7)

          • 無(wú)法獲取資源(例如:網(wǎng)絡(luò)斷)

          通過(guò)拋出異常來(lái)向調(diào)用者表明函數(shù)無(wú)法執(zhí)行指定的任務(wù)。


          不應(yīng)該使用異常的情況

          循環(huán)的正常終止,處理的正常結(jié)束都是正常和期待的動(dòng)作,不應(yīng)該被視為異常。這種做法可以保證錯(cuò)誤處理和“普通的代碼”分離。C++編譯器會(huì)以異常處理很罕見(jiàn)為前提進(jìn)行代碼優(yōu)化。不要使用將拋出異常作為從函數(shù)中返回結(jié)果的另一種方式使用。


          使用異常時(shí)應(yīng)防止資源泄露

          資源泄露通常都是不可接受的。如果只是簡(jiǎn)單的去掉原有的錯(cuò)誤處理代碼并增加異常拋出和處理代碼,通常會(huì)發(fā)生資源泄露。例如下面的代碼:

          void leak(int x)   // don't: may leak{    auto p = new int{7};    if (x < 0) throw Get_me_out_of_here{};  // may leak *p    // ...    delete p;   // we may never get here}

          手動(dòng)釋放資源雖然不是完全做不到,但是工作量巨大且容易引發(fā)錯(cuò)誤。

          void f2(int i)   // Clumsy and error-prone: explicit release
          {
          int* p = new int[12];
          // ...
          if (i < 17) {
          delete[] p;
          throw Bad{"in f()", i};
          }
          // ...
          }

          這樣的代碼過(guò)于冗長(zhǎng),甚至比不用異常的代碼更加冗長(zhǎng)。在更大規(guī)模的,存在更多的拋出異常的可能性的代碼中,顯式釋放資源會(huì)更加繁復(fù)和易錯(cuò)。解決這個(gè)問(wèn)題的方法RAII(“資源請(qǐng)求即初始化”),它是防止泄露最簡(jiǎn)單,更加系統(tǒng)化的方式。

          void f3(int i)   // OK: resource management done by a handle (but see below)
          {
          auto p = make_unique(12);
          // ...
          if (i < 17) throw Bad{"in f()", i};
          // ...
          }

          另外一個(gè)解決方案(通常更好)是用局部變量來(lái)避免使用指針。

          void no_leak_simplified(int x){    vector v(7);    // ...}


          定義和使用自己的異常類(lèi)型

          使用用戶(hù)定義類(lèi)型的好處是幾乎和其他人的異常發(fā)生沖突。這種問(wèn)題在代碼規(guī)模變大之后會(huì)在不知不覺(jué)出現(xiàn)。繼承自exception的標(biāo)準(zhǔn)庫(kù)類(lèi)應(yīng)該只用于基類(lèi)或只要求“通常”處理的異常。和內(nèi)置類(lèi)型相似,對(duì)它們的使用也有可能和其他人的使用發(fā)生沖突。


          使用常量引用形式捕捉繼承體系中的異常

          為了避免數(shù)據(jù)截?cái)唷?/span>大多數(shù)處理程序不會(huì)改變異常的內(nèi)容,因此通常我們同時(shí)推薦使用常量形式。


          正確排列catch子句

          catch子句按照它們表示的次序行,一個(gè)子句處理之后,其他子句不再執(zhí)行。

          void f()
          {
          // ...
          try {
          // ...
          }
          catch (Base& b) { /* ... */ }
          catch (Derived& d) { /* ... */ }
          catch (...) { /* ... */ }
          catch (std::exception& e) { /* ... */ }
          }

          如果Deriveds是Base的派生類(lèi),捕捉派生類(lèi)的處理永遠(yuǎn)不會(huì)執(zhí)行。捕捉所有異常的處理會(huì)導(dǎo)致捕捉std::exception的處理程序永遠(yuǎn)不會(huì)執(zhí)行。


          重新拋出異常

          重新拋出已經(jīng)捕獲的異常時(shí)一定要使用throw;而不是throw e;。使用后者會(huì)拋出一個(gè)e的新拷貝(靜態(tài)類(lèi)型std::exception的截?cái)嘟Y(jié)果)而不是重新拋出原始異常。


          關(guān)于noexcept

          為了讓錯(cuò)誤處理更系統(tǒng)化,健壯和高效可以為函數(shù)定義noexcept。因?yàn)槟扯未a有不會(huì)拋出異常的操作構(gòu)成,所以我們知道某函數(shù)不會(huì)拋出異常。通過(guò)將函數(shù)定義為noexcept,我向編譯器和代碼的讀者傳遞了可以讓它們更容易理解和維護(hù)的信息。很多標(biāo)準(zhǔn)庫(kù)函數(shù)被定義為noexcept,包含所有從C標(biāo)準(zhǔn)庫(kù)繼承的標(biāo)準(zhǔn)庫(kù)函數(shù)。

          但應(yīng)該注意的是,一旦定義了noexcept,C++編譯器就會(huì)放棄為函數(shù)生成接受、轉(zhuǎn)發(fā)異常的處理。如果實(shí)際發(fā)生了異常,結(jié)果是毀滅性的。一定要慎重定義noexcept。


          析構(gòu)函數(shù),內(nèi)存釋放和swap操作永遠(yuǎn)不能失敗

          如果析構(gòu)函數(shù)、swap操作或者內(nèi)存釋放失敗了,我們不知道如何編寫(xiě)可信賴(lài)的處理程序;也就是說(shuō),如果它因?yàn)楫惓M顺龌蛘咧皇菦](méi)有執(zhí)行要求的操作。標(biāo)準(zhǔn)庫(kù)假設(shè)析構(gòu)函數(shù),內(nèi)存釋放函數(shù)(例如delete運(yùn)算符),swap都不會(huì)拋出異常。如果它們異常,標(biāo)準(zhǔn)庫(kù)的前提條件就被破壞了。


          不要試圖在所有函數(shù)中捕捉所有異常

          在一個(gè)無(wú)法提供有意義的恢復(fù)操作的函數(shù)中捕捉錯(cuò)誤會(huì)導(dǎo)致代碼復(fù)雜化和冗余。讓異常向外傳播直到到達(dá)一個(gè)可以處理它的函數(shù)。讓RAII處理調(diào)用路徑上的清理動(dòng)作。

          try/catch結(jié)構(gòu)冗長(zhǎng),非平凡的用法容易出錯(cuò)。try/catch可以看作是非系統(tǒng)化和低層次資源管理或錯(cuò)誤處理的信號(hào)。

          最小限度顯式使用try/catch。


          無(wú)法使用異常的情況

          有些系統(tǒng),例如硬實(shí)時(shí)系統(tǒng)要求保證一個(gè)動(dòng)作在開(kāi)始執(zhí)行之前就能確定其執(zhí)行時(shí)間小于某個(gè)固定值(通常很小)。這樣的系統(tǒng)只有在存在某種可以準(zhǔn)確預(yù)測(cè)系統(tǒng)從拋出異常過(guò)程中恢復(fù)的最大時(shí)間的工具時(shí)才可以使用異常。如果沒(méi)有適當(dāng)?shù)臅r(shí)間評(píng)價(jià)工具,異常處理機(jī)制很難滿(mǎn)足這個(gè)要求。這樣的系統(tǒng)(例如飛行控制系統(tǒng))通常也會(huì)禁止使用動(dòng)態(tài)(堆)內(nèi)存。


          不要使用拋異常聲明

          拋異常聲明本來(lái)的目的是明確表明某個(gè)函數(shù)可能拋出的異常。

          int use(int arg)
          throw(X, Y)
          {
          // ...
          auto x = f(arg);
          // ...
          }

          但是異常聲明讓錯(cuò)誤處理更脆弱,并強(qiáng)制產(chǎn)生運(yùn)行時(shí)成本,已經(jīng)從C++標(biāo)準(zhǔn)中被移除了。在不會(huì)拋出任何異常時(shí),使用noexcept或者和它等價(jià)的throw()是才更加正確的做法


          關(guān)于異常代價(jià)和性能

          很多關(guān)于異常的大量恐懼都是被誤導(dǎo)的。當(dāng)在沒(méi)有被指針或復(fù)雜的控制結(jié)構(gòu)搞亂的代碼環(huán)境中使用異常時(shí),異常處理幾乎總是可以接受的(無(wú)論是時(shí)間還是空間維度),幾乎總是可以帶來(lái)更好的代碼。

          在譴責(zé)異常或抱怨異常的成本過(guò)高之前,考慮使用錯(cuò)誤代碼時(shí)的成本和復(fù)雜度。如果你擔(dān)心性能,進(jìn)行測(cè)量(而不是無(wú)根據(jù)的懷疑,譯者注)


          參考資料

          C++核心準(zhǔn)則英文原文(C++之父Bjarne Stroustrup的技術(shù)文章):

          https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md


          異常相關(guān)翻譯文章匯總:

          https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&album_id=1575975158413099008&__biz=MzI2MDYyNDgzMQ==#wechat_redirect

          更多中文翻譯請(qǐng)參考本人公眾號(hào)【面向?qū)ο笏伎肌俊?/span>


          新書(shū)介紹

          以下是本人最近出版的新書(shū),拜托多多關(guān)注!

          本書(shū)利用Python 的標(biāo)準(zhǔn)GUI 工具包tkinter,通過(guò)可執(zhí)行的示例對(duì)23 個(gè)設(shè)計(jì)模式逐個(gè)進(jìn)行說(shuō)明。這樣一方面可以使讀者了解真實(shí)的軟件開(kāi)發(fā)工作中每個(gè)設(shè)計(jì)模式的運(yùn)用場(chǎng)景和想要解決的問(wèn)題;另一方面通過(guò)對(duì)這些問(wèn)題的解決過(guò)程進(jìn)行說(shuō)明,讓讀者明白在編寫(xiě)代碼時(shí)如何判斷使用設(shè)計(jì)模式的利弊,并合理運(yùn)用設(shè)計(jì)模式。


          對(duì)設(shè)計(jì)模式感興趣而且希望隨學(xué)隨用的讀者通過(guò)本書(shū)可以快速跨越從理解到運(yùn)用的門(mén)檻;希望學(xué)習(xí)Python GUI 編程的讀者可以將本書(shū)中的示例作為設(shè)計(jì)和開(kāi)發(fā)的參考;使用Python 語(yǔ)言進(jìn)行圖像分析、數(shù)據(jù)處理工作的讀者可以直接以本書(shū)中的示例為基礎(chǔ),迅速構(gòu)建自己的系統(tǒng)架構(gòu)。




          覺(jué)得本文有幫助?請(qǐng)分享給更多人。

          關(guān)注微信公眾號(hào)【面向?qū)ο笏伎肌枯p松學(xué)習(xí)每一天!

          面向?qū)ο箝_(kāi)發(fā),面向?qū)ο笏伎迹?/span>



          瀏覽 59
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  操老骚逼视频 | 亚洲色婷婷久久精品AV蜜桃 | 欧美aa视频 | 亚洲成人h | 男人的天堂网av 男人天堂无码视频 |