11

爲什麼爲什麼當其他構造函數存在時,「ctor()= default」更改行爲?

struct wrapper 
{ 
    explicit wrapper(void *); 
    wrapper() = default; 
    int v; 
}; 

int main() { return wrapper().v; } // You should run this in Debug mode 

回報0xCCCCCCCC,而

struct wrapper { wrapper() = default; int v; }; 
int main() { return wrapper().v; } 

struct wrapper { int v; }; 
int main() { return wrapper().v; } 

都返回0

+1

當您添加非默認構造函數時,類型不再是聚合。我相信這是在玩這個,不知道如何。無論如何,我懷疑你保證它是0。 –

+0

@RyanHaining:你確定嗎?如果是這樣的話,這似乎很奇怪,因爲這意味着只有當你沒有其他構造函數時纔可以使用'= default',這似乎毫無意義...... – Mehrdad

+0

'= default'將返回默認的構造函數,但在這兩種情況下'v'都是非空間化的。有了gcc,即使在第一種情況下,我也能得到0,但這只是偶然。 –

回答

4

值初始化,如果T是無需用戶提供的或刪除的缺省-構造函數的類型,則該對象是零初始化(第8.5節/ 8.2)。 wrapper的確如此。

你的第一示例實現零初始化(第8.5節/ 6.1,重點煤礦)

第三殼體相匹配 - 如果T是標量類型(3.9),該對象被初始化爲值通過將整數文字 0(零)轉換爲T而獲得;

- 如果T是一個(可能是cv限定的)非聯合類類型,則每個非靜態數據成員和每個基類子對象都被初始化並且填充被初始化爲零位;

- 如果T是一個(可能CV修飾)聯合類型,對象的第一非靜態命名的數據成員是零初始化和填充被初始化爲零比特;

- 如果T是一個數組類型,每一個元素是零初始化

- 如果T是引用類型,則執行

在第一示例

所以沒有初始化,v應被初始化爲零。這看起來像一個錯誤。

在你的第二個和第三個例子中,你不再有用戶提供的構造函數,但是你有一個非用戶提供或刪除的默認構造函數,所以你的例子仍然屬於第零個初始化,它是對每個非靜態數據成員進行零初始化。 VS在那裏是正確的。

+0

C++ 11標準中存在缺陷。如果你閱讀IS,它會說「沒有用戶提供的構造函數」,它缺少關鍵的「默認」。 – dyp

+0

@dyp:什麼是「IS」? – Mehrdad

+6

@Mehrdad:噢,最近已經變得曖昧了 - 我指的是國際標準。另請參閱:http://open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1301 – dyp

4

這似乎確實是MSVC中的一個錯誤。在所有三種情況wrapper無用戶提供默認的構造,所以初始化與wrapper()調用:

(所有的n3690引文)

(8.5/11),它的初始值設定的目標是一空的圓括號,即(),應進行數值初始化。

(感謝DYP),這將導致int v零intialization

初始化然後指我們的規則:

(8.5/8)如果T是一個(可能cv-qualified)類的類型,沒有用戶提供或刪除的默認構造函數,那麼該對象將被初始化並檢查默認初始化的語義約束。

零初始化規則狀態:

(8.5/6)如果T是一個(可能CV修飾)非工會類型,每個非靜態數據成員,並且每個基礎類子對象零初始化和填充被初始化爲零位

int v是的wrapper數據成員根據爲零initialiazed本身:

(8.5/6)如果T是一個標量類型(3.9),該對象被初始化爲通過轉換整數文字而得到的值0(零)到T

哪個不是你觀察行爲。

+0

如果你能解釋爲什麼GCC和Clang正在經歷額外的麻煩,如果你認爲VC++是正確的而不是這樣做的話,那麼就會初始化所有的東西。 – Mehrdad

+0

@Mehrdad我翻轉了所有的東西 –

+0

@dyp這是我曾經(推到)擊中的最微妙的C++點。 –

相關問題