2015-06-27 92 views
22

考慮下面的代碼中,我們基於對D另一部分初始化的D部分:數組成員是否可以自我初始化?

struct c { 
    c() : D{rand(), D[0]} {} 
    int D[2]; 
}; 

int main() { 
    c C; 
    assert(C.D[0] == C.D[1]); 
} 

在上述程序明確定義?我們可以安全地使用同一個數組的一部分來初始化它的另一部分嗎?

+5

我的第一個想法是「不要」。我的第二個想法是「初始化程序列出havr命令gurantees」。我的第三個想法是「初始化發生在論證評估之後,不是嗎?」 – Yakk

回答

11

數組成員是否可以自我初始化?

是。

struct c { 
    int a[3]; 
    c() : a{4, a[0], 3} {} // a[0] is initialized to 4. 
          // a[1] is initialized to whatever a[0] is. (4) 
          // a[2] is initialized to 3. 
}; 

但考慮這個例子:

struct c { 
    int a[3]; 
    c() : a{a[1], 4, a[1]} {} // a[0] is initialized to whatever a[1] is.(Garbage value) 
           // a[1] is initialized to 4. 
           // a[2] is initialized to what a[1] is now (4). 
}; 

在這裏,在a的第一個元素將是任何值是a[1], 這將很可能是垃圾的價值。 第二個元素被初始化爲4,第三個元素被初始化爲 ,現在是a[1],它的值是4

此外,當你不列出未列出的{}, 元素中的陣列中的所有元素,將被默認初始化:

struct c { 
    int a[5]; // notice the size 
    c() : a{a[1], 2, 3, 4}{} // a[0] will get value that is in a[1] 
           // but since a[1] has garbage value, 
           // it will be default initialized to 0. 
           // a[1] = 2 
           // a[2] = 3 
           // a[3] = 4 
           // a[4] is not listed and will get 0. 
}; 

然而,上市已經初始化的元素會給你你想要的價值。
使用上面的例子:

struct c { 
    int a[5]; 
    c() : a{1, a[0], 3, 4}{} // a[0] = 1 
           // a[1] = 1 
           // a[2] = 3 
           // a[3] = 4 
           // a[4] is not listed and will get 0. 
}; 
16

當聚合(包括數組)從一個支撐列表初始化時,每個聚合元素都從列表的相應元素(「增加下標或成員順序」)進行初始化。儘管我找不到一個確切的規則,說每個元素的初始化都是在前一個元素之後進行排序的,但標準中有一個例子清楚地表明這是預期的意思。該例子是在[dcl.init.aggr]:

struct S { int a; const char* b; int c; int d = b[a]; }; 
S ss = { 1, "asdf" }; 

初始化ss.a1ss.b"asdf"ss.c與表單int{}(即,0)的表達式的值,和ss.dss.b[ss.a]的值(即,’s’

+3

[dcl.init.list]/4:「在加載初始化列表的初始化程序列表中,初始化程序子句,包括從包 擴展(14.5.3)產生的任何結果子句,按照也就是說,與給定的初始化子句相關的每個值計算和副作用在每個值計算之前被排序,並且在與初始值設定項的逗號分隔列表中的任何初始化子句相關聯的任何初始值 - 清單「。 – Casey

+2

@Casey:副作用是否包括聚合成員的初始化? –

+0

初始化當然是一個副作用,聲稱副作用與給定的*初始化子句*相關並不是不合理的。鑑於沒有任何相反的語言,我認爲這是預期的解釋。 – Casey

0

它不是寫一個很好的做法因爲當構造函數運行時,不需要首先執行rand()將執行 然後D [0],這一切都取決於編譯器,D [0]可能是 首先執行,在這種情況下,d [ 1]將包含垃圾值。它 完全取決於編譯器,它可以先編譯第二個參數 ,然後第一個參數或反之亦然,執行此 語句可能會導致未知行爲。

+3

標準很清楚'rand()'在'D [0]'之前被調用,所以你是不正確的:il不是finction調用,你會正確的。在讀取'D [0]'之前初始化'D [0]'還不太清楚。 – Yakk

+1

我目前正在學習C++,我已經閱讀了C++ primer中的這種行爲,我使用的是一本書,在書中明確指出哪個參數首先被執行是未知行爲,並且它不是一個很好的做法,關於初始化的其他參數 –

+3

是來自某處的引用,或者你爲什麼將它放在塊引用中?如果是這樣,請正確歸因(標題,頁面,作者,網址等)。 – Bergi

2

根據cppreference.com

集合初始化的效果是:

每個數組元素或非靜態類成員,在類定義數組 標/出現的順序,從 初始化器列表的相應子句複製初始化。

你的代碼似乎很好。 但有點混淆。

+0

爲什麼會令人困惑? – emlai

+0

在我看來,它降低了可讀性,許多人不知道他們會按順序進行評估。 – deepmax

相關問題