2012-02-06 91 views
12

我刷新我的價值初始化與默認初始化的理解,和整個this傳來:爲什麼這個簡單的賦值未定義的行爲?

struct C { 
    int x; 
    int y; 
    C() { } 
}; 

int main() { 
    C c = C(); 
} 

顯然,這是UB因爲

在C()的情況下,有一個構造函數能夠對 初始化x和y成員,因此不會進行初始化。嘗試將C()複製到c因此會導致未定義的行爲。

我想我明白爲什麼,但我不能肯定。有人可以詳細說明嗎?

難道說這也是UB?

int x; x = x; 

順便說一句,關於價值初始化,以下保證爲零?

int x = int(); 
+0

不確定你的意思。如果你的意思是x和y的值將被初始化,那麼是的,但是你已經回答了你自己的問題(因爲構造函數沒有這樣做)。至於C c = C();我認爲這完全有效。 – Sid 2012-02-06 16:42:22

+0

我認爲這是完全有效的,直到有人聲稱否則。當我讀到它時,第一個片段只能通過UB,如果第二個片段也是這樣,否則它是一個簡單的未初始化的值,沒有鼻甲。 – spraff 2012-02-06 16:45:05

+2

@Sid:不,使用未初始化對象的值會導致未定義的行爲。 – 2012-02-06 16:54:45

回答

13

你的第一個例子是未定義行爲,因爲默認情況下,編譯器生成 拷貝構造函數會做一個成員複製,int S可有 誘捕值,並讀取捕獲值複製它可能會導致 程序崩潰。

在實踐中,我無法想象這居然過崩潰;編譯器 幾乎肯定會優化複製出來,即使它沒有,它 可能會使用一些特殊的按位副本將複製而不 檢查誘捕值。 (在C++中,您保證能夠以 複製字節。)

對於第二種情況,同樣是未定義的行爲。雖然在這種情況下, 你有賦值而不是複製結構,編譯器 不太可能優化它。 (有一個在你的第一個 例如不分配,只複製建築。)

對於第三個,是的。用空parenthese(並且沒有 用戶定義的默認初始值重寫它)一個初始化第一執行零 初始化(完全是發生用於與靜態壽命變量)。

+0

+1,某些調試工具在虛擬機中運行應用程序,該虛擬機會陷入(在某些情況下)將其識別爲潛在問題。但我同意,在真實情況下,您可能會複製未初始化的內存並移動它。 – 2012-02-06 17:00:09

+0

在C++ 14中,引用是[dcl.init]/12「]如果通過評估產生了不確定的值,除了在以下情況下的 以外,行爲是未定義的:」 - 且沒有任何情況涵蓋此代碼 – 2016-04-18 22:32:49

-1

不會的。大多數編譯器會優化變量設置,但不會改變x的值。它與以下代碼相同:

int x = 0; 
x = 0; 

這不是第二行不會執行,它只是不會執行任何操作。

+0

問題是,如果我發佈的片段是UB,那麼編譯器優化可能會導致* any *結果。 – spraff 2012-02-06 16:46:06

+3

我不同意,在技術上從未設定值讀取是未定義的行爲。編譯器是否優化了讀取是未定義行爲的可能結果之一。 – 2012-02-06 16:49:01

1

我不認爲這實際上是undefined behavior,儘管c中的值有unspecified values。也就是說,只要你沒有最終使用這些未指定的值,程序的行爲就會被很好地定義。如果你使用它們,例如在一個條件或打印它們,結果沒有定義。不過,我認爲該計劃不允許做任何奇怪的事情。

關於在內置類型上使用默認構造函數,這將保證產生類型的零值,即整數的0,浮點類型的0.0等。這也延伸到沒有構造函數。一旦有任何構造函數,你需要照顧構造你的成員,而無需使用構造函數。

+1

Ooh,你與詹姆斯坎澤在一場直gun槍戰中!他說複製構造函數「使用」未初始化的值,並且這樣做是UB。你說別的。 – 2012-02-06 17:18:38

+0

@SteveJessop,但這個答案似乎更正確,不是嗎? :),+1 – 2012-08-22 14:43:22

+0

@Anubis先生:在最高級別似乎存在分歧,你可以在C++中使用未初始化的值。標準中有一些文字說你不能執行左值右值轉換,但有人會認爲(與其他對象表示法一樣),你可以用'unsigned char'來訪問它。在實踐中,生成的副本不太可能會盲目地複製數據,但爲了安全起見,我相信詹姆斯對標準允許的內容是正確的。例如,複製可能偶然檢查奇偶校驗位,如果「int」有任何的話,如果它們是錯誤的,則使用UB。 – 2012-08-22 16:18:45

相關問題