操屁眼的视频在线免费看,日本在线综合一区二区,久久在线观看免费视频,欧美日韩精品久久综

新聞資訊

    原文發表于,由本人翻譯整理分享于此。

    前言

    我已經使用了本文描述的代碼和機制近20年了,到目前為止,我還沒有找到更好的方法來處理大型C++項目中的錯誤。最初的想法是從一篇文章(Dr Dobbs 2000年)中摘錄出來的。我已經添加了一些新內容進去ai處理對象外觀時出錯,使它更容易在生產環境中使用。

    寫這篇文章的沖動是最近發表在的C++博客。正如我們在本文后面將看到的那樣,使用錯誤代碼對象可以產生更清晰、更易于維護的代碼。

    背景

    每個C++程序員都知道處理異常情況的傳統方法有兩種:第一種是從良好的舊C風格繼承而來,返回錯誤代碼,并希望調用者進行判斷并采取適當的操作;第二種方法是拋出異常,并希望周圍代碼塊捕獲并處理該異常。C++ FAQ強烈支持第二種方法,認為它會使得代碼更安全。

    然而,使用異常也有其自身的缺點。代碼變得更加復雜,用戶必須知道所有可能引發的異常。這就是為什么舊的C++規范在函數聲明中添加了“異常規范”。此外,異常會降低代碼的效率。

    錯誤代碼對象被設計成類似于傳統C錯誤代碼的函數返回。最大的區別是,如果不進行判斷,它們就會拋出異常。

    讓我們舉個小例子,看看不同的實現會是什么樣的。

    首先,采用傳統錯誤碼的經典C方法:

    int my_sqrt (float& value) {
      if (value < 0)
        return -1;
      value = sqrt(value);
      return 0;
    }
     
    int main () {
      double val = -1;
      // 注意,這里已經進行了返回值得檢查
      if (my_sqrt (val) == -1)
        printf ("square root of negative number");
      // 有些人會忘記返回值檢查
      my_sqrt (val);
      // 這時候斷言出錯,因為我們沒有檢查返回值
      assert (val >= 0);
    }
    

    如果不檢查結果,所有的壞事情都會發生,我們必須準備好使用所有傳統的調試工具來找出問題。

    使用傳統C++異常,相同的代碼可能如下所示:

    void my_sqrt (float& value) {
      if (value < 0)
        throw std::exception ();
      value = sqrt(value);
    }
    int main () {
      double val = -1;
    

    ai選擇單個對象_ai處理對象外觀時出錯_ai貼齊對象

    // 注意,這里已經捕獲異常 try { my_sqrt (val); } catch (std::exception& x) { printf ("square root of negative number"); } // 有些人可能會忘記捕獲異常 my_sqrt (val); // 這時候斷言出錯,因為我們沒有捕獲異常 assert (val >= 0); }

    異常處理在這樣一個小例子中非常有用,因為我們可以看到函數使用try...catch包裹。但是,如果函數被深埋在庫中,你可能不知道它可能拋出哪些異常。請注意,從函數簽名中根本不知道它會拋出什么異常(如果它有拋出異常的話)。

    現在.……咳咳..……錯誤代碼對象(erc)登場:

    erc my_sqrt (float& value) {
      if (value < 0)
        return -1;
      value = sqrt(value);
      return 0;
    }
    int main () {
      double val = -1;
      // 注意,這里進行返回值檢查
      if (my_sqrt (val) == -1)                    // (1)
        printf ("square root of negative number");
      // 如果你喜歡異常處理,也是可以的
      try {
        my_sqrt (val);
      } catch (erc& x) {
        printf ("square root of negative number");
      }
      // 有些人可能忘記檢查返回值
      my_sqrt (val);                              // (2)
      // 程序會崩潰,因為有一個未捕獲的異常
    

    ai選擇單個對象_ai處理對象外觀時出錯_ai貼齊對象

    assert (val >= 0); }

    在深入了解這種方法的魔力之前,請先觀察幾點:

    初窺Error Code對象

    我們先來一個全貌展示,暫時忽略一些細節,后續再細講。

    當創建一個erc對象時,它有一個整數值(就像C錯誤代碼)和一個活動標志。

    class erc
    {
    public:
      erc (int val) : value (val), active (true) {};
    //...
    private:
      int value;          // 一個整數值
      bool active;        // 一個活動標志
    }
    

    如果釋放erc對象時,活動標志被設置,則析構函數將會引發異常。

    class erc
    {
    public:
      erc (int val) : value (val), active (true) {}
       
      // 析構函數檢查活動標志,決定是否拋出異常
      ~erc () noexcept(false) {if (active) throw *this;}
    //...
    private:
      int value;
      bool active;
    }
    

    到目前為止,仍然沒有什么特別之處:這僅僅是一個在析構函數中拋出異常的對象。也因為如此,我們必須使用(false)來修飾析構函數。

    整數轉換運算符則返回erc對象的整數值,并重置活動標志:

    class erc
    {
    public:
      erc (int val) : value (val), active (true) {}
      ~erc () noexcept(false) {if (active) throw *this;}
      
      // 整數轉換運算符,返回整數值,重置活動標志
      operator int () {active = false; return value;}
      
    

    ai貼齊對象_ai處理對象外觀時出錯_ai選擇單個對象

    //... private: int value; bool active; }

    由于活動標志已被重置,當erc對象超出作用域時,析構函數將不再拋出異常。通常,當對錯誤代碼進行檢查時,將調用整數轉換運算符。

    回顧一下前面簡單的用法示例,在標記為(1)的注釋算處,函數返回的erc對象與整數值進行比較,從而調用整數轉換運算符。因此,活動標志將被重置,并且析構函數不會拋出異常。在標記為(2)的注釋處,函數返回的erc對象,由于設置了活動標志,析構函數將引發異常。

    遵循公認的Unix慣例,正如亞里士多德所說,成功的方法只有一種,那就是數值‘0’表示成功。erc對象的數值為0則不拋出異常。任何其他數值都表示失敗,并拋出異常(如果沒有檢查返回值)。

    這是錯誤代碼對象的整個概念的精髓,如Dobbs 的文章所示。然而,我無法抗拒接受一個簡單的想法并使它變得更復雜的誘惑;繼續閱讀!

    更多細節

    前面只是全貌展示,忽略了一些細節。這些細節使錯誤代碼功能更完善,便于把它集成到大型項目中。首先,我們需要一個移動構造函數和一個移動賦值操作符。目的是把活動標志傳遞給新對象,并使原對象的活動標志失效,確保只有一個活動的erc對象。

    為了便于處理,我們還需要將錯誤代碼分類的組件,這個組件是通過error 對象()實現。除了數值和活動標志屬性之外,Erc還具有一個對象和一個嚴重性級別。Erc析構函數并不像我們前面那樣直接拋出異常,而是調用::raise函數ai處理對象外觀時出錯,與對象關聯起來。在這個raise函數中,比較erc對象的嚴重性級別和對象關聯的日志級別。如果erc對象的級別高于對象的日志級別,則::raise()函數調用::log()函數生成錯誤信息并拋出異常,或在超過預設級別時只記錄錯誤信息。嚴重性級別是從UNIX 函數借用的:

    名字數值動作

    0

    總是不記錄,不拋出

    1

    默認不記錄,不拋出

    2

    默認不記錄,不拋出

    3

    默認記錄,不拋出

    4

    默認記錄,拋出

    5

    默認記錄,拋出

    6

    默認記錄,拋出

    7

    總是記錄,拋出

    默認情況下,錯誤代碼與默認的對象關聯。但是,我們也可以定義不同的類,重新處理錯誤。例如,您可以為所有套接字錯誤定義一個專門的錯誤處理類,該類把錯誤代碼轉換為有意義的消息。具有不同的錯誤級別有利于測試或調試,通過改變某一類錯誤的拋出或日志記錄級別。

    一個更實用的例子

    這篇博客文章前面提到的,一個HTTP客戶端程序的基本流程:

    Status get_data_from_server(HostName host)
    

    ai選擇單個對象_ai貼齊對象_ai處理對象外觀時出錯

    { open_socket(); if (failed) return failure(); resolve_host(); if (failed) return failure(); connect(); if (failed) return failure(); send_data(); if (failed) return failure(); receive_data(); if (failed) return failure(); close_socket(); // 有資源漏的可能 return success(); }

    這里有個問題是,因為套接字沒有關閉函數就返回,會產生資源泄漏。在這種情況下,讓我們看看如何使用錯誤代碼(指作者寫的Erc)。

    如果我們想使用異常,代碼可以如下所示:

    // 函數聲明,返回值得使用erc
    erc open_socket ();
    erc resolve_host ();
    erc connect ();
    erc send_data ();
    erc receive_data ();
    erc close_socket ();
    erc get_data_from_server(HostName host)
    {
      erc result;
      try {
        // 這些函數調用失敗,會觸發異常
        open_socket ();
        resolve_host ();
    

    ai貼齊對象_ai處理對象外觀時出錯_ai選擇單個對象

    connect (); send_data (); receive_data (); } catch (erc& x) { result = x; // 返回erc對象給外部調用者 } close_socket (); // 清理 return result; }

    毫無例外,相同的代碼可以寫成:

    // 函數聲明,返回值使用erc
    erc open_socket ();
    erc resolve_host ();
    erc connect ();
    erc send_data ();
    erc receive_data ();
    erc close_socket ();
    erc get_data_from_server(HostName host)
    {
      erc result;
      (result = open_socket ())
      || (result = resolve_host ())
      || (result = connect ())
      || (result = send_data ())
      || (result = receive_data ());
      close_socket ();      // 清理
      result.reactivate ();
      return result;
    }
    

    在上面的片段中,已轉換為整數,因為它必須參與邏輯或表達式。此轉換重置活動標志,因此我們必須再次顯式打開它,方法是調用()功能。如果所有函數調用都是成功的,那么結果就是0,而且,按照慣例它不會拋出異常。

    最后

    附件的源代碼是高質量的、經過合理優化的,希望它不會更很難使用。演示項目是對流行的數據庫的C++包裝器。演示項目比較大,因為它包含了最新版本的代碼(截至本文編寫時,2019年11月)。源代碼和演示項目都包括 文檔。

    歷史

    2019年11月12日:初版

    源碼和演示項目

    code - 6.9 KB

    demo - 2.2 MB

網站首頁   |    關于我們   |    公司新聞   |    產品方案   |    用戶案例   |    售后服務   |    合作伙伴   |    人才招聘   |   

友情鏈接: 餐飲加盟

地址:北京市海淀區    電話:010-     郵箱:@126.com

備案號:冀ICP備2024067069號-3 北京科技有限公司版權所有