Guru of the Week 條款20:程式碼的複雜性(第一部分) (轉)
GotW #20 Code Complexity – Part I:namespace prefix = o ns = "urn:schemas--com::office" />
著者:Herb Sutter
翻譯:K ][ N G of @rk™
[宣告]:本文內容取自網站上的Guru of the Week欄目,其著作權歸原著者本人所有。譯者kingofark在未經原著者本人同意的情況下翻譯本文。本翻譯內容僅供自學和參考用,請所有閱讀過本文的人不要擅自轉載、傳播本翻譯內容;本翻譯內容的人請在閱讀瀏覽後,立即刪除其。譯者kingofark對違反上述兩條原則的人不負任何責任。特此宣告。
Revision 1.0
Guru of the Week 條款20:程式碼的複雜性(第一部分)
難度:9 / 10
(本條款提出了一個有趣味的挑戰:在一個簡單得只有三行程式碼的裡可以有多少條路經?其答案几乎將肯定讓你吃驚。)
[問題]
在沒有任何其它附加資訊的情況下,下列程式碼中可以有多少條執行路經?
String EvaluateSalaryAndReturnName( Employee e )
{
if( e.Title() == "CEO" || e.Salary() > 100000 )
{
cout << e.First() << " " << e.Last()
<< " is overpaid" << endl;
}
return e.First() + " " + e.Last();
}
[解答]
假設:
a) 忽略對函式引數求值時的不同順序以及由解構函式(destructor)丟擲的異常。[注1]
下面的問題提給無所畏懼的勇者:
如果允許解構函式丟擲異常,那麼共會有多少條執行路經呢?
b) 的函式被認為具有原子性。事實上,例如”e.Title()”這個呼叫就可能由於好幾個原因而丟擲異常(比如,它自己本身可能丟擲異常;它也可能由於「未能捕獲由其呼叫的另一個函式所丟擲的異常」而丟擲異常;或者它可能採用return by value(傳值返回)方式從而造成臨時得建構函式可能丟擲異常)。這裡我們假設對於函式而言,只關注執行e.Title()操作的結果,即完成該操作後是否丟擲了異常。
解答:23(僅僅在4行程式碼裡!)
如果你找到了 給自己評等級
---------------------------------------------------------------------
3 平均水平(Average)
4-14 能夠認知異常(Exception-Aware)
15-23 精英資質(Guru Material)
這23條執行路徑包括:
——3條與異常無關的(non-exceptional)路徑
——20條暗藏的路徑,都與異常有關
要理解那3條普通路徑,訣竅就是要知道C/C++的“短路求值規則(Short-Circuit Evaluation Rule)”:
1. 如果e.Title()==”CEO”,那麼就不需要對第二個條件求值了(比如,e.Salary()將不會被呼叫),但cout還是會被執行的。[注2]
2. 如果e.Title()!=”CEO”但e.Salary()>100000,那麼兩個條件都會被求值,cout也會被執行。
3. 如果e.Title()!=”CEO”且e.Salary()<=100000,那麼cout將不會被執行。
下述都是由異常引出的執行路徑:
String EvaluateSalaryAndReturnName( Employee e )
^*^ ^4^
4. 引數採用pass by value(值傳遞)方式,這將喚起Employee copy constructor。這個copy操作可能丟擲異常。
*. 在將函式臨時的返回值複製到函式呼叫者的區域時,String的copy constructor可能丟擲異常。然而在這裡我們忽略這種可能性,因為其是在函式外部發生的(何況從目前的情形來看,現有的執行路徑已經夠我們忙的了!)
if( e.Title() == "CEO" || e.Salary() > 100000 )
^5^ ^7^ ^6^ ^11^ ^8^ ^10^ ^9^
5. 成員函式Title()本身就可能丟擲異常;或者其採用return by value方式返回class type的物件,從而導致複製操作可能丟擲異常。
6. 為了與有效的operator==相匹配,字串也許需要被轉換成class type(或許與e.Title()的返回型別相同)的臨時物件,而這個臨時物件的構造過程可能丟擲異常。
7. 如果operator==是由員提供的函式,那麼它可能丟擲異常。
8. 與#5類似,Salary()本身可能丟擲異常,或者由於其返回臨時物件而造成在臨時物件的構造過程中丟擲異常。
9. 與#6類似,可能需要構造臨時物件,而這個構造過程可能丟擲異常。
10. 與#7類似,這或許是由程式設計師提供的函式,那麼它可能丟擲異常。
11. 與#7和#10類似,這或許是由程式設計師提供的函式,那麼它可能丟擲異常。
cout << e.First() << " " << e.Last()
^17^ ^18^
<< " is overpaid" << endl;
12-16 如C++標準草案所述,這裡的五個對operator<
17-18 與#5類似。First()和/或Last()可能丟擲異常,或者由於其返回臨時物件而造成在物件的構造過程中可能丟擲異常。
return e.First() + " " + e.Last();
^19^ ^22^^21^ ^23^ ^20^
19-20 與#5類似。First()和/或Last()可能丟擲異常,或者由於其返回臨時物件而造成在物件的構造過程中可能丟擲異常。
21.與#6類似,可能需要構造臨時物件,而這個構造過程可能丟擲異常。
22-23 與#7類似,這或許是由程式設計師提供的函式,那麼它可能丟擲異常。
本期GotW條款的目的是演示「在一個允許異常機制的語言中,簡單的程式碼裡可以存在多少條暗藏的執行路徑」。這種暗藏的複雜性會影響函式的可靠性和可測性嗎?請在下一期GotW中尋找這個問題的答案。
[注1]:決不允許一個異常從解構函式中滲透出來。如果允許這樣做,程式碼將無法正常工作。請看我在C++Report Nov/Dec 1997中有關的更多討論:Destructors That Throw and Why They're Evil。
[注2]:如果對==、||和>予以正確恰當的過載(overload),那麼在if語句中,||或許是一個函式呼叫。如果其是一個函式呼叫,那麼“短路求值規則”會被抑住,這樣if語句中的所有條件將總是被求值。
(完)
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-1007738/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Guru of The week #20 程式碼的複雜性 Ⅰ. (轉)
- Guru of the Week 條款21:程式碼的複雜性(第二部分) (轉)
- Guru of the Week 條款16:具有最大可複用性的通用Containers (轉)AI
- Guru of the Week 條款07:編譯期的依賴性 (轉)編譯
- Guru of the Week 條款22:物件的生存期(第一部分) (轉)物件
- Guru of the Week 條款19:自動轉換 (轉)
- Guru of the Week 條款27:轉呼叫函式 (轉)函式
- Guru of the Week 條款13:物件導向程式設計 (轉)物件程式設計
- Guru of the Week 條款28:“Fast Pimpl”技術 (轉)AST
- Guru of the Week 條款09:記憶體管理(上篇) (轉)記憶體
- Guru of the Week 條款10:記憶體管理(下篇) (轉)記憶體
- Guru of the Week 條款24:編譯級防火牆 (轉)編譯防火牆
- Guru of the Week 條款30附錄:介面原則 (轉)
- Guru of the Week 條款23:物件的生存期(第二部分) (轉)物件
- Guru of the Week 條款14:類之間的關係(上篇) (轉)
- Guru of the Week 條款15:類之間的關係(下篇) (轉)
- Guru of the Week 條款05:覆寫虛擬函式 (轉)函式
- Guru of the Week 條款08:GotW挑戰篇——異常處理的安全性 (轉)Go
- Guru of the Week 條款11:物件等同(Object Identity)問題 (轉)物件ObjectIDE
- C++ articles:Guru of the Week #1 (轉)C++
- Guru of the week:#18 迭代指標. (轉)指標
- Guru of the week:#17 型別對映. (轉)型別
- Guru of the week:#19 自動型別轉換. (轉)型別
- C++ articles:Guru of the Week #4 -- Class Mechantics (轉)C++
- Guru of the Week #5:虛擬函式的重新定義 (轉)函式
- C++ articles:Guru of the Week #3:使用標準庫 (轉)C++
- 降低程式碼的圈複雜度——複雜程式碼的解決之道複雜度
- 如何無痛降低 if else 麵條程式碼複雜度複雜度
- 重構遺留程式碼(3):複雜的條件語句
- 淺析程式碼圈複雜度及認知複雜度複雜度
- git管理複雜專案程式碼Git
- 用程式碼複雜度分析風險複雜度
- 計算複雜性(Computing Complexity) (轉)
- 第一講 複雜度分析複雜度
- 複雜的行列轉換
- 20款前端特效及部分原始碼前端特效原始碼
- 如何降低軟體的複雜性?
- 解決DDD核心的複雜性