2012-05-24 88 views
0

比方說,我寫了一個類Foo與構造函數Foo(int)。 我有這段代碼:C++:類/結構體是否在編譯時初始化?

Foo a(i), b = a + Foo(2); 

如果我調用的代碼構造以恆定的,例如Foo(2),編譯器是否運行一次並將結果存儲爲運行時,還是在運行時執行?無論結構/類是否僅包含POD數據類型,它是一樣的嗎?

假設它在運行時執行(我認爲是這種情況),有沒有辦法使它在編譯時運行,或者具有與運行時相同的效果?

編輯:恐怕我沒有說清楚。我指的是代碼的Foo(2)部分,它是完全不可變的。另外,我無法使用C++ 11(我正在使用GCC 4.1並且無法升級),所以constexpr雖然有效,但不適合我。

+0

這是在全球範圍或功能? –

+3

查看'constexpr' –

+0

我正在考慮函數內的例子。我擔心不得不多次評估'Foo(2)'。 –

回答

0
Foo a(i), b = a + Foo(2); 

此初始化發生在運行時,而不是在編譯時。

編譯時初始化僅適用於內置類型,如果它們的初始化程序可以在編譯時計算,或者它們被聲明爲全局變量,或者作爲static。在後兩種情況下,它們在編譯時是零初始化的。我已經在這裏詳細解釋這一點:

-1

這發生在運行時。如果你希望它在編譯時發生,那麼你需要對這個值進行硬編碼。

0

已編譯的代碼可能在執行過程中的不同位置被調用。一旦代碼被編譯,Foo(2)的值可能是不可變的。

+1

downvote不是因爲你錯了,而是因爲我不明白你在說什麼。 –

+0

也是錯的。 'Foo(2)'的值可能取決於構造的時間,因此不是編譯時常量。 – MSalters

3

很可能有你的a使用constant initialization,這是靜態初始化,但要做到這一點:

  1. i大部分是常量表達式
  2. Foo::Foo(int)必須constexpr
  3. 任何/所有其他Foo:Foo(int)使用的函數/計數器也必須是constexpr

同樣將是非常多的情況下,你b - Foo(2)必須是constexpr,並Foo::operator+(Foo const &)Foo operator+(Foo const &, Foo const &)(無論你有)將不得不constexpr

常量表達式的定義在C++ 11標準的§5.19中,以防您想要更詳細地調查。我的猜測是,如果Foo非常簡單,那麼可能是a,但我對b的確信度低很多。

3

假設我用一個構造函數Foo(int)編寫了一個Foo類。我有這段代碼:

Foo a(i), b = a + Foo(2); 

如果我調用的代碼構造以恆定的,沒有編譯器運行一次,並存儲運行時的結果,或者是它在運行 - 執行時間?

有兩個層面的:

  • 是有可能和法律w.r.t.標準的完善優化器 - 實現家居專家的人可能具有無限的努力和天才做的 - 要做到這一點,在編譯時, 和
  • 是必需的編譯時行爲/由標準保證

i編譯時間常量?如果不是,並且傳遞給Foo::Foo(i)i的值影響其行爲(無論是影響數據成員值還是像記錄日誌這樣的副作用),那麼顯然在編譯時構建Foo(i)本質上是不可能的。如果i是恆定的,那麼它可能仍然是不可能的 - 例如構造函數實現可能具有基於當前時間的行爲,或需要查閱其他一些運行時數據。這些問題也可能會阻止在編譯時進行評估。

i如果是恆定的,並且Foo的構造不依賴於其它只運行時間數據,那麼它是可能優化。但是,您的代碼中沒有任何內容需要C++標準甚至嘗試進行任何優化,更不用說能夠優化這一點了。在Foo上調用的+運算符也是如此......優化可能是合法的,但肯定不是必需的。

實際上,我希望大多數當前的主流編譯器優化編譯時常量iFoo(i)的簡單情況,但要解決這個問題。如果你真的想知道,嘗試它在各種優化級別的編譯器....

假設它在運行時執行(我相信是這種情況),有沒有辦法使它在編譯時運行,還是具有與運行時相同的效果?

是......你可能會得到一些milage出constexpr,這與推出的關鍵字C++ 11,告訴它需要在編譯時(解決某些價值觀的編譯器,如果你constexpr變量/值即編譯器不需要在編譯時支持它將報告錯誤)。其次,通常可以使用模板來表達編譯時間操作。爲了讓自己開始朝這個方向發展,您可能需要搜索「C++模板階乘編譯時間」或類似的內容,以瞭解如何編碼基本計算。

+1

正確答案。如果'Foo'是'int'和'operator +(Foo,Foo)'的簡單包裝,它只是一個類型安全的'int + int',編譯器甚至可能會優化那個位。 – MSalters

2

適用「假設」規則,即規則說明編譯器可以做任何它喜歡的事情,只要程序的可觀察行爲與標準中描述的行爲相同即可。

如果:

  • Foo構造是在TU可見,
  • 所以是析構函數~Foo
  • 他們都不具有任何副作用,
  • 其結果穿上」 t取決於需要在運行時解決的任何事情(比如時間,或者一些非const對象的值,我們知道的所有對象都可能在代碼執行時被修改過),
  • operator+是可見的,並且不會做任何事情來讓RHS的地址「轉義」爲未知代碼,或者將其地址用於可觀察行爲(例如打印出來),或者做任何其他需要對象在那裏,

然後足夠聰明的優化器可以消除Foo(2)暫時完全,何operator+使用RHS的數據成員,只是用它知道這些成員將擁有的任何值。

或者,作爲較小的優化,它可以將值放入程序的數據部分的Foo實例的佈局中,並將其作爲Foo(2)使用。我想這就是你通過存儲運行時結果的意思。

這樣的優化實際上是否完全是特定於實現的,並且取決於您使用的編譯器以及哪些標誌。反彙編代碼,看看真的發生了什麼。

可以確保Foo(2)在C++ 03只計算一次,如果你這樣做:是(根據標準),在運行時計算

static Foo foo2(2); 
Foo a(i), b = a + foo2; 

foo2,第一時間代碼執行。同樣,編譯器可以在編譯時調用「as-if」規則來完成部分或全部計算,但這也不是必需的。