2017-04-23 125 views
3

假設我們有一個循環迭代很多次:在循環體內聲明一個變量是否有缺點?

for (int i=0; i < 1000000; ++i) { 
    int s = 100; 
    s += i; 
    cout << s; 
} 

我們只使用s循環體裏面,所以我們非常希望有聲明它,所以它不會污染封閉命名空間。

我想知道是否有任何缺點。例如,它是否會產生性能成本,因爲程序在每次迭代中重新聲明s

+2

是的每一次迭代它將被構建和銷燬 – deW1

+0

@ deW1:謝謝,我在我的問題中修復了它。我不打算讓它成爲UB。 –

+1

@ deW1雖然對於簡單的類型,但我有興趣聽到關於編譯器如何優化的權威答案。 – jwimberley

回答

7

從概念上說該變量在每次迭代時被構造和破壞。

但它會影響性能嗎?那麼,你可以檢查你的情況right here。在第7行刪除int以在循環局部變量和函數局部變量之間切換。
結論:沒有什麼區別。大會是一樣的!

所以,只要使用你的代碼中有意義的東西。如果您每次迭代需要一個對象,請爲每個對象創建一個對象。優化器比你想象的更聰明。如果這還不夠,你會回到它的數據分析和仔細調整,而不是寬泛的指導方針。

+0

輝煌。因此從概念上講,它是不同的,理論上講,它可能會導致性能損失,但實際上,現代編譯器應該能夠優化這一點。 –

+1

@DunPeal。即使在看過相當多的C++之後,我仍然經常被編譯器從其帽子中優化出來。儘可能使用'const'並調整優化級別,您將看到奇蹟。 – Quentin

2

是的。在循環中聲明一個變量將導致它在每次迭代時被解構和重構。對於小循環和簡單的數據類型,編譯器可以優化,但是在使用複雜對象和大循環時,最好在外部聲明變量。

如果循環的變量使用太多的內存,則可以將循環和聲明放在大括號中,這樣會在退出後刪除大括號內分配的所有變量。大多數情況下,這種微觀優化並不重要,但如果您使用複雜的類等,只需使用外部初始化變量並每次重置即可。

一般來說,聲明太多變量並不是一個好主意,它會讓你的代碼難以閱讀並增加內存使用量。如果可以的話,不要在不需要時聲明變量。例如,您的示例可以簡化爲for(int i = 0;i<1000000;i++)cout<<i+100;。如果這樣的優化是可能的並且他們不會讓你的代碼難以閱讀,那就使用它們。

+1

*「你的例子可以簡化爲'for(int i = 100; y <1000100; y ++){cout << i}'。」*對於讀者:值得注意的是,一個體面的編譯器可能會弄清楚這一點,優化,就好像代碼是這樣寫的。我的建議通常主要是爲了人類可讀性編碼,並且只有在分析發現瓶頸後才進行優化。 – cdhowie

+0

@cdhowie我說編譯器通常優化這些循環,如果你的循環非常複雜,你只應該擔心這一點。 – theo2003

+2

如果變量讓你的代碼更難閱讀,那麼你可能會濫用/誤用它們。例如,將+100摺疊到循環頭文件中會混淆數字偏移的迭代次數。海事組織這其實不太清楚。 – Quentin

1

銷燬int是一個noop。變量不再存在,但不需要運行代碼。

不存在的變量的引用或指針具有未定義的行爲。在初始化之前,新創建的局部變量具有未定義的狀態。因此,簡單地重新使用舊變量是合法的,編譯器不必證明沒有這樣突出的引用。

在這種情況下,如果它可以證明值是恆定的100,它甚至可以跳過除第一次初始化之外的所有內容。它可以「儘早」進行初始化,因爲沒有明確的方法可以及早發現它。在這種情況下,這很容易,大多數編譯器都可以輕鬆完成。在更復雜的情況下,更少。如果將它標記爲const,編譯器不再需要證明它是未修改的,而是可以假定它!

爲了使某些優化變得簡單,C++中的許多未定義區域都存在。

現在,如果你有更復雜的東西,比如vector<int>{1,2,3,4,5},破壞和創造就會變得不那麼簡單。將變量從循環中提取出來仍然是可能的,但對編譯器來說則更加困難。這是因爲動態分配有時難以優化。

相關問題