偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

C++的另一種錯(cuò)誤處理策略

開(kāi)發(fā) 后端
這篇短文是討論一個(gè)大多數(shù)程序員都感興趣的一個(gè)話題:錯(cuò)誤處理。錯(cuò)誤處理是編程的一個(gè)“黑暗面”。它既是應(yīng)用程序的“現(xiàn)實(shí)世界”的關(guān)鍵點(diǎn),也是一個(gè)你想隱藏的復(fù)雜業(yè)務(wù)。

這篇短文是討論一個(gè)大多數(shù)程序員都感興趣的一個(gè)話題:錯(cuò)誤處理。錯(cuò)誤處理是編程的一個(gè)“黑暗面”。它既是應(yīng)用程序的“現(xiàn)實(shí)世界”的關(guān)鍵點(diǎn),也是一個(gè)你想隱藏的復(fù)雜業(yè)務(wù)。

在早期的C編程生涯中,我知道三種錯(cuò)誤處理的方式。

C語(yǔ)言的方式:返回錯(cuò)誤碼

C語(yǔ)言風(fēng)格的錯(cuò)誤處理是最簡(jiǎn)單的,但是并不***。

C語(yǔ)言風(fēng)格的錯(cuò)誤處理依賴(lài)于“當(dāng)程序遇到錯(cuò)誤時(shí)返回一個(gè)錯(cuò)誤碼”。這里是一個(gè)簡(jiǎn)單的例子:

  1. int find_slash(const char *str) 
  2.     int i = 0; 
  3.    
  4.     while (str[i] && str[i] != '/'
  5.           i++; 
  6.    
  7.     if (str[i] == '\0'
  8.         return -1; //Error code 
  9.    
  10.     //True value 
  11.     return i; 
  12.    
  13. // . . . 
  14.    
  15. if (find_slash(string) == -1) 
  16.         //error handling 

使用這種方式的有什么好處?

你可以在調(diào)用函數(shù)之后直接處理錯(cuò)誤碼(在C語(yǔ)言中,你也會(huì)這樣處理),顯示一個(gè)錯(cuò)誤消息或者直接終止程序。或者僅僅恢復(fù)程序最近的一個(gè)狀態(tài),終止計(jì)算。

當(dāng)你找不到錯(cuò)誤處理在哪里的時(shí)候,你只需要后頭看看函數(shù)調(diào)用,錯(cuò)誤處理就在那個(gè)附近。

使用這種方式有什么不好?

有人可能會(huì)告訴你,這種異常/錯(cuò)誤處理方式和“執(zhí)行邏輯”混在了一起。當(dāng)你順序地閱讀這些代碼的時(shí)候就行程序執(zhí)行一樣,你看到了一會(huì)錯(cuò)誤處理,一會(huì)程序執(zhí)行。這樣很糟糕,你可能更喜歡只讀程序執(zhí)行邏輯或者錯(cuò)誤處理邏輯。

并且你被限定使用錯(cuò)誤碼,如果你想要提供更多的信息,你需要?jiǎng)?chuàng)建一些功能函數(shù)比如:errstr或者提供全局變量。

使用C++的方式

C++作為對(duì)C的增強(qiáng),引入了一種新的錯(cuò)誤處理方式——異常。異常通過(guò)拋出一個(gè)錯(cuò)誤的方式來(lái)中斷正常代碼執(zhí)行邏輯,并可以被其他地方所捕獲。下面是一個(gè)簡(jiǎn)單的例子:

  1. int find_slash(const char *str) 
  2.     int i = 0; 
  3.    
  4.     while (str[i] && str[i] != '/'
  5.           i++; 
  6.    
  7.     if (str[i] == '\0'
  8.         throw AnException("Error message"); 
  9.    
  10.     //True value 
  11.     return i; 
  12.    
  13. // . . . 
  14.    
  15. try 
  16.     find_slash(string); 
  17. catch(AnException& e) 
  18.    //Handle exception 

這樣做的好處?

程序邏輯和錯(cuò)誤處理分離了。一邊你可以看到函數(shù)是如何工作的,而另一邊你可以看到函數(shù)失敗時(shí)候是怎么處理的。這樣做很***,可以很容易看出錯(cuò)誤處理和正常程序邏輯。

另外,現(xiàn)在你可以為你的錯(cuò)誤提供你需要的盡可能多的信息,因?yàn)槟憧梢詫⑿枰膬?nèi)容填充在自定義異常對(duì)象里。

這樣做的壞處

編寫(xiě)詳盡的異常處理變得很冗。你需要一個(gè)異常樹(shù),但是***不要太大,這樣,你可以選擇捕獲感興趣的異常。同時(shí),內(nèi)部需要提供錯(cuò)誤碼,來(lái)獲知究竟發(fā)生了什么,同時(shí)需要檢索一些錯(cuò)誤消息,等等。編寫(xiě)寫(xiě)異常類(lèi)通常都是冗長(zhǎng),這是將信息嵌入到錯(cuò)誤里來(lái)靈活處理更多的信息的成本。

這里的錯(cuò)誤處理哲學(xué)是將錯(cuò)誤盡可能推遲到需要處理的地方再處理,當(dāng)你不知道程序執(zhí)行過(guò)程究竟哪里會(huì)產(chǎn)生一個(gè)錯(cuò)誤,你需要跳過(guò)不同的文件和功能函數(shù)來(lái) 查找,這通常都是困難的,如果你在一個(gè)很深的調(diào)用樹(shù)(這里意思是當(dāng)你將函數(shù)調(diào)用繪制出一個(gè)圖形,其形狀類(lèi)似一棵樹(shù))上引發(fā)了一個(gè)異常,你需要指定在哪里來(lái) 處理這個(gè)異常,當(dāng)它被處理的時(shí)候,它又是在哪里發(fā)生的。特別是當(dāng)你的程序很大,又是很早之前編寫(xiě),有恰巧設(shè)計(jì)不夠良好的時(shí)候,就更加顯得困難。而大多數(shù)商 業(yè)項(xiàng)目都是這樣。

所以我覺(jué)得“異常是危險(xiǎn)的”。雖然它提供了一種良好的方式來(lái)處理錯(cuò)誤——僅限于一些小項(xiàng)目,并且這里的調(diào)用圖簡(jiǎn)單且易于掌握時(shí)候。

#p#

錯(cuò)誤封裝的模式

我這里把它叫做一種模式,所以人們不必害怕?lián)?。后面,我?huì)給它一種更好的命名,所以請(qǐng)不要著急。

錯(cuò)誤封裝的主旨是創(chuàng)建一種封裝來(lái)包含錯(cuò)誤消息或者錯(cuò)誤的返回值。我們通常會(huì)選擇字符串而不是其他,因?yàn)檫@也并不容易實(shí)現(xiàn)。我們盡力保證語(yǔ)法的可讀性,可理解,并且容易應(yīng)用。我們不處理拷貝構(gòu)造或者多參數(shù)函數(shù)及返回值,這里僅給出一個(gè)盡可能簡(jiǎn)單的例子。

讓我們以下面的例子開(kāi)始:

  1. E<int> find_slash(const char* str) 
  2.     int i = 0; 
  3.    
  4.     while (str[i] && str[i] != '/'
  5.           i++; 
  6.    
  7.     if (str[i] == '\0'
  8.         return fail<int>("Error message"); 
  9.    
  10.     //True value 
  11.     return ret(i); 
  12.    
  13. // . . . 
  14.    
  15. auto v = find_slash(string); 
  16. if(!v) 
  17.     //Handle exception 
乍一看,這里有點(diǎn)類(lèi)似C語(yǔ)言的風(fēng)格,但是不是,為表明這一點(diǎn),請(qǐng)看接下來(lái)的多個(gè)函數(shù)調(diào)用例子:
  1. E<int> find_slash(const char*); 
  2. E<int> do_some_arithmetic(int); 
  3. E<std::string> format(int); 
  4. E<void> display(std::string); 
  5.    
  6. auto v = ret(string) 
  7.          .bind(find_slash) 
  8.          .bind(do_some_arithmetic) 
  9.          .bind(format) 
  10.          .bind(display); 
  11.    
  12. if(!v) 
  13.     //Handle error 

好了,這里發(fā)生了什么?bind是一個(gè)成員函數(shù)來(lái)綁定你的函數(shù)調(diào)用,試著去應(yīng)用它。如果錯(cuò)誤裝箱里面含有一個(gè)值,那么它就應(yīng)用于函數(shù)調(diào)用,繼續(xù)返回一個(gè)錯(cuò)誤裝箱(編譯器不允許你返回一個(gè)不帶錯(cuò)誤裝箱的函數(shù))。

所以,我們鏈?zhǔn)秸{(diào)用了find_slashe,do_some_arithmetic, format和display.它們都不處理錯(cuò)誤裝箱,由于bind函數(shù)的作用,我們將函數(shù)E<something_out> f(something_in)返回結(jié)果給E<something_out> f(E<something_in>)函數(shù)做參數(shù)。

這里的好處是什么?

再一次,函數(shù)邏輯(調(diào)用鏈)和錯(cuò)誤處理分離了。和異常一樣,我們可以簡(jiǎn)單讀一下函數(shù)調(diào)用鏈來(lái)了解代碼邏輯,而不用關(guān)心執(zhí)行是在哪里被中斷的。事實(shí)上,函數(shù)調(diào)用鏈可以在任何調(diào)用時(shí)被中斷。但是我們可以認(rèn)為沒(méi)有錯(cuò)誤發(fā)生,如果我們的邏輯是正確的,可以很快速檢查。

當(dāng)然,類(lèi)型推導(dǎo)會(huì)阻止你在調(diào)用display之后繼續(xù)進(jìn)行綁定。所以我們也沒(méi)有失去類(lèi)型能力。

注意,我們沒(méi)有在其他地方調(diào)用這些函數(shù),我們?cè)?**將這些方法組裝在一起。這里是關(guān)鍵,你應(yīng)該編寫(xiě)一些小的模塊函數(shù)(另外,注意:你應(yīng)該編寫(xiě)模板函 數(shù)使其工作)接收一個(gè)值,然后計(jì)算一個(gè)新值或者返回失敗。在每一步中,你都不需要考慮可能出現(xiàn)錯(cuò)誤導(dǎo)致你的控制流中斷,并且校驗(yàn)?zāi)闶欠裨谝粋€(gè)有效的狀態(tài)上 (異常安全基于查詢(xún)每個(gè)函數(shù)調(diào)用,指出函數(shù)是否中斷你的控制流程,如果出現(xiàn)異常會(huì)發(fā)生什么),基于這一點(diǎn),這樣做更安全。

和異常一樣,我們可以處理很詳細(xì)的信息,盡管這里我們編寫(xiě)的是一個(gè)偏模板函數(shù),所以也容易理解一些。

我們可以很容易放置異常處理邏輯,把它放在函數(shù)調(diào)用鏈之后(除非這個(gè)返回值還需要進(jìn)一步被鏈接)。現(xiàn)在,我們有一個(gè)大的的執(zhí)行流,沒(méi)有中斷,使用小 的函數(shù)處理流程,容易定位。當(dāng)需要添加一個(gè)新的錯(cuò)誤時(shí),你只需找到那些函數(shù),通過(guò)函數(shù)調(diào)用鏈,你可以直接定位到處理位置,并根據(jù)需要添加。大型項(xiàng)目變得更 加的線性化,并且更易讀。

這樣做有什么不足?

首先,這是一個(gè)新的處理方式,并且和C++的方式不兼容。這不是一個(gè)標(biāo)準(zhǔn)處理方法,當(dāng)你使用stl時(shí),你仍然需要使用異常。

對(duì)于我來(lái)說(shuō),這樣做還是有點(diǎn)冗長(zhǎng)。需要顯式編寫(xiě)fail<int>(…)的模板推導(dǎo)顯得有點(diǎn)怪異,如果你有個(gè)多態(tài)錯(cuò)誤類(lèi)型就更糟了,你不得不這樣寫(xiě)fail<return_type, error_type>("...").

當(dāng)函數(shù)有多個(gè)參數(shù)時(shí)編寫(xiě)也很困難,在其他一些語(yǔ)言中,可以使用適用類(lèi)型和抽象類(lèi)型很好地解決這個(gè)問(wèn)題,不過(guò)這在C++中不會(huì)提供。我想更適合使用bind2(E<a>, E<b>, f)bind3(E<a>, E<b>, E<c>, f),可變模板參數(shù)功能更有用。

為獲取封裝錯(cuò)誤中的值,我們需要檢查這個(gè)值是否是有效值,接著調(diào)用一個(gè)“to_value”方法。我們沒(méi)辦法不通過(guò)檢查來(lái)做到這一點(diǎn)。我們希望的是“解構(gòu)”一個(gè)對(duì)象,不過(guò)這在C++中不支持,這也不是一些可以說(shuō)“我們把它加入到下一個(gè)標(biāo)準(zhǔn)”的特性。

目前為止,我不知道讀者是否有方法將其適配到成員函數(shù)中,如果你有想法,請(qǐng)測(cè)試一下,如果可以,請(qǐng)告知我們。

實(shí)現(xiàn)原子錯(cuò)誤處理

我實(shí)現(xiàn)了它,我定義了這個(gè)黑魔法的名字——“原子化”,你可以認(rèn)為“原子化”是一個(gè)對(duì)值和錯(cuò)誤上下文的裝箱,比如,一個(gè)box包含一個(gè)值或者什么也不包含是一個(gè)原子組(這里作為一個(gè)練習(xí),你可以試著實(shí)現(xiàn)一下)。

有點(diǎn)奇怪的是,從某個(gè)角度來(lái)說(shuō)隊(duì)列是一個(gè)原子組,他們擁有一個(gè)上下文的值。

讓我們從上面的E模版類(lèi)實(shí)現(xiàn)開(kāi)始,這里使用了C++11標(biāo)準(zhǔn)中的decltype和auto -> decltype類(lèi)型,允許自動(dòng)推導(dǎo)得到表達(dá)式的類(lèi)型,這非常有用。

這里的bind函數(shù)有點(diǎn)怪異,但是他實(shí)現(xiàn)了我剛才提到的內(nèi)容。

原文鏈接:http://zenol.fr/site/2013/08/27/an-alternative-error-handling-strategy-for-cpp/

譯文鏈接:http://blog.jobbole.com/54699/

責(zé)任編輯:陳四芳 來(lái)源: 伯樂(lè)在線
相關(guān)推薦

2013-05-22 15:31:07

AOP的CGlib實(shí)現(xiàn)

2014-09-17 14:37:06

2018-04-18 07:34:58

2023-06-18 23:19:17

ChatGPTPPT方式

2010-07-21 16:23:09

運(yùn)行telnet程序

2011-12-29 21:28:31

Metro UI

2016-03-03 10:29:31

用戶(hù)信息改進(jìn)

2016-07-11 16:18:26

互聯(lián)網(wǎng)

2019-01-02 08:04:29

GAN損失函數(shù)神經(jīng)網(wǎng)絡(luò)

2013-09-30 10:13:08

IT女程序員

2011-07-21 14:17:15

Ceylon

2009-06-17 09:05:05

Linux隱藏網(wǎng)絡(luò)鏈接命令

2010-09-02 09:14:35

CSS浮動(dòng)

2015-07-28 13:36:04

2009-06-17 12:01:21

Linux

2013-10-21 15:11:15

OrmsqlOrm設(shè)計(jì)

2013-09-12 14:26:47

百度云網(wǎng)盤(pán)

2010-06-09 16:17:20

TCP IP協(xié)議網(wǎng)絡(luò)故

2019-03-17 15:59:05

Android PAPIAPP

2010-01-21 16:24:02

C++語(yǔ)言
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)