2015-06-05 60 views
6

clang++永不允許default initialization of a const variable of class-type without a user-defined constructor; g++稍有限制(見下文)。根據this answer,這是因爲POD類型「未默認初始化」。如果我理解正確,這意味着默認初始化不會調用默認構造函數,也不會調用值初始化,因此POD類型內的數據成員不會被初始化。當然,它有一個const POD類型的未初始化值是沒有意義的,因爲它們可以初始化從不,因此不安全使用。何時以及如何默認初始化常量變量?

有這種情況的幾個變種:​​

  1. 類型在技術上是「POD」,但不包含數據成員(僅適用於函數)。使用{}clang++不認爲這是一次特殊的情況下,也沒有,我覺得,做標準,但g++確實允許的話,即使在構造標記explicit。)
  2. 一個空的構造函數定義。 (這是clang頁面上描述問題的推薦解決方法。)
  3. 默認構造函數聲明爲=default。 (C++ 11以後;類型仍然被認爲是POD,所以編譯器和標準都沒有把它當作一種特殊情況)
  4. 使用{}明確調用了聚合初始化,如果我理解正確的話,它會變成值初始化。 (C++ 11起;兩種編譯器,而且我認爲,標準允許這種)

在第一種情況下,不可能有初始化成員,因此目前還不清楚爲什麼的任何實例類本身將被視爲「未初始化」,無論它是否爲const。由於g++允許這種行爲,使用安全嗎?爲什麼它被clang++和標準禁止? (以及是否有任何其他情況下,g++允許POD默認初始化其中clang++不?)

在第二和第三種情況下,使用{}代替=default似乎很奇怪,我的要求。 編輯:this question很好地解釋了這種差異,所以我刪除了問題中關於區別的部分。 (我仍然認爲這是語言的一個非常令人困惑的方面,雖然)。

最後,將Foo f{}總是零初始化的內置類型,如果是Foo::Foo(void){}=default,或隱式聲明的成員?

+0

是否有沒有成員變量的const POD類型的用例?你可以使用非const類型的函數,因爲沒有可能被錯誤修改的成員。 –

+0

@MattMcNabb我不確定。這是一種在同事的代碼中,模板工廠函數(或類似的東西)中重複出現的模式。我會盡量記住明天問那位同事明天的意圖是什麼。 –

+0

用'{}'定義的構造函數不是一個簡單的構造函數。 – 0x499602D2

回答

5

由於g ++允許這種行爲,它使用起來安全嗎?

安全的是什麼意思?目前顯然不是便攜式的。但是,它不會給你g ++上的意想不到的結果。

爲什麼禁止使用clang ++和標準?

假設委員會在C++ 98中放入「用戶提供的構造函數必須」規則時沒有考慮它,或者認爲特殊外殼空POD類不符合規範的複雜性;鏗鏘++只是遵循標準。但是,標準是likely going to change,只要構造函數實際上會初始化每個子對象,則更一般地允許您編寫const Foo f;

最後,將Foo f{};總是零初始化,如果Foo::Foo(void){}=default,或隱式聲明的內置 類型成員?

對於後兩者是。第一個沒有。這個算作用戶提供,因此在調用默認構造函數之前,值初始化不會執行零初始化。

+0

在「意想不到的結果」意義上,我確實的意思是「安全」。再一次,很好的開放標準鏈接;你如何快速找到那些(或者完全)?另外,當你說「在調用默認構造函數之前,值初始化不會執行零初始化」,你的意思是零初始化不會(必然)發生*完全*?因此,從'= default'改爲'{}'實際上可能會引入不正確的初始化錯誤? –

+0

@KyleStrand 1)這個特殊的g ++/clang ++差異在SO之前就已經被問到過了,所以我知道這裏有一個開放的核心問題:) 2)是的,它不能保證發生,儘管實現可以破壞內存它喜歡(因爲沒有明確定義的程序可以觀察它)。從技術上講,它是不確定的,讀取它會導致UB(以'unsigned char'爲例)。 3)是的。 –