1. 程式人生 > >Guru of the Week 條款20:程式碼的複雜性(第一部分)

Guru of the Week 條款20:程式碼的複雜性(第一部分)

GotW #20 Code Complexity – Part I<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

著者:Herb Sutter

翻譯:K ][ N G of @rk™

[宣告]:本文內容取自www.gotw.ca網站上的Guru of the Week欄目,其著作權歸原著者本人所有。譯者kingofark在未經原著者本人同意的情況下翻譯本文。本翻譯內容僅供自學和參考用,請所有閱讀過本文的人不要擅自轉載、傳播本翻譯內容;下載本翻譯內容的人請在閱讀瀏覽後,立即刪除其備份。譯者

kingofark對違反上述兩條原則的人不負任何責任。特此宣告。

Revision 1.0

Guru of the Week條款20:程式碼的複雜性(第一部分)

難度:9 / 10

(本條款提出了一個有趣味的挑戰:在一個簡單得只有三行程式碼的函式裡可以有多少條執行路經?其答案几乎將肯定讓你吃驚。)

[問題]

在沒有任何其它附加資訊的情況下,下列程式碼中可以有多少條執行路經?

[解答]

 

假設:

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將不會被執行。

 

下述都是由異常引出的執行路徑:

4.引數採用pass by value(值傳遞)方式,這將喚起Employee copy constructor。這個copy操作可能丟擲異常。

 

*.         在將函式臨時的返回值拷貝到函式呼叫者的區域時,Stringcopy constructor可能丟擲異常。然而在這裡我們忽略這種可能性,因為其是在函式外部發生的(何況從目前的情形來看,現有的執行路徑已經夠我們忙的了!)

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類似,這或許是由程式設計師提供的函式,那麼它可能丟擲異常。

12-16C++標準草案所述,這裡的五個對operator<<的呼叫都可能丟擲異常。

17-18#5類似。First()/Last()可能丟擲異常,或者由於其返回臨時物件而造成在物件的構造過程中可能丟擲異常。

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語句中的所有條件將總是被求值。

(完)