2012-09-19 119 views
4

我經常看到其他函數被多次調用而不是一次性存儲函數結果的函數。函數調用與局部變量

(1)

void ExampleFunction() 
{ 
    if (TestFunction() > x || TestFunction() < y || TestFunction() == z) 
    { 
     a = TestFunction(); 
     return; 
    } 
    b = TestFunction(); 
} 

相反,我會寫這樣的說法,(2)

void ExampleFunction() 
{ 
    int test = TestFunction(); 
    if (test > x || test < y || test == z) 
    { 
     a = test; 
     return; 
    } 
    b = test; 
} 

我認爲第2版是更好的閱讀和更好進行調試。 但我想知道爲什麼人們喜歡1號? 有什麼我沒有看到?性能問題? 當我看到它時,我發現在最壞的情況下,數字(1)中有4個函數調用,而不是數字(2)中的1個函數調用,因此性能在數字(1)中應該更差,不是嗎?

+10

問問編寫代碼的人! –

+2

編譯器可能會將代碼優化爲您的替代方案,因此性能不成問題。我的自我,我發現第一個選擇其實更可讀。 –

+6

可能有副作用,意味着必須每次調用函數。所以你的問題的答案是:這取決於。 – Default

回答

1

我認爲版本2更好的閱讀和更好的調試。

同意。

所以表現應該更糟(1),不是嗎?

不一定。如果TestFunction足夠小,那麼編譯器可能決定優化多個呼叫。在其他情況下,績效是否重要取決於調用ExampleFunction的頻率。如果不經常,則優化維護性。

此外,TestFunction可能有副作用,但在這種情況下,代碼或註釋應該以某種方式使其清晰。

+0

好的謝謝,這對我有意義。無論如何,我想到了沒有副作用的功能。 所以我想我會用數字(2)去。因爲讀取和調試更好,並且性能可能會更好(如果不能內聯)。 – DanielG

+0

據我所知,編譯器現在包含[鏈接時優化](http://gcc.gnu.org/projects/lto/lto.pdf),這意味着它們應該能夠優化這樣的代碼,即使「TestFunction '在與'ExampleFunction'不同的翻譯單位中定義。 –

+0

@LucTouraille:我認爲這幾乎侷限於Intel C.謝謝! –

1

這兩個不相等。舉個例子:

int TestFunction() 
{ 
    static int x; 
    return x++; 
} 

理智世界雖然,這不會是這樣的,我同意第二個版本是更好的。 :)

如果函數由於某種原因不能被內聯,第二個函數甚至會更有效。

3

我會使用(2)如果我想強調在整個代碼中使用相同的值,或者如果我想強調該值的類型是int。強調真實但不明顯的事情可以幫助讀者快速理解代碼。

我會使用(1)如果我不想強調這些事情中的任何一種,特別是如果它們不是真實的,或者由於副作用而調用TestFunction()的次數很重要。

顯然如果你強調的是目前是真的,但是在將來TestFunction()更改並且它變成了false,那麼你有一個bug。所以我也想要自己控制TestFunction(),或者對作者的未來兼容性計劃有一定的信心。通常這種信心很容易:如果TestFunction()返回CPU數量,那麼您很樂意爲該值拍攝快照,並且您也很樂意將它存儲在int中,而不管它實際返回的是什麼類型。你必須對將來的兼容性有一個最低限度的信心來使用一個函數,例如,請確信它將來不會返回鍵盤的數量。但是不同的人有時會有不同的想法,什麼是「突變」,特別是當界面沒有準確記錄時。因此,對TestFunction()的重複呼叫有時可能是一種防禦性編程。

+1

如果要刪除「強調'int」「,可以使用」auto「代替。 –

+0

@larsmans:是的,甚至在'TestFunction'返回一個引用的情況下甚至是'auto&'。 –

+0

強調它的一個可能原因是,在閱讀比較時,您需要知道涉及的類型是有符號的,無符號的還是其中的一種。所以這是強調這種類型的原因,而不是放在'TestFunction'上。即使假設讀者在IDE中並且可以輕鬆查找類型,他們可能會從知道*您知道您期望的類型中受益。 'auto'非常有用,並且命名該類型也非常有用,每個都取而代之。 –

2

當使用臨時存儲這樣一個非常簡單的表達式的結果時,可以認爲臨時存在應該消除的不必要的噪聲。

Martin Fowler在他的書"Refactoring: Improving the Design of Existing Code"中列出了這種臨時消除作爲一種可能有益的重構(Inline temp)。

不管這是一個好主意,取決於很多方面:

  • 是否臨時通過一個有意義的名稱提供了比原來更多的表達的信息,例如?
  • 性能重要嗎?正如你所指出的,沒有臨時的第二個版本可能是效率更高(大多數編譯器應該能夠優化這樣的代碼,以便函數只被調用一次,假設它沒有副作用)。
  • 函數後面是否臨時修改? (如果不是,它可能應該const

最後,引入或去除這種臨時選擇的是,應該在逐案基礎上作出的決定。如果它使代碼更具可讀性,請將其保留。如果只是噪音,請將其移除。在你的特定例子中,我會說暫時不會增加很多,但是如果不知道實際代碼中使用的真實姓名,這很難說清楚,你可能會感覺不到。