2009-11-21 57 views
8

在以下代碼片段中,d1的初始化程序傳遞了尚未構造的d2(正確?),D的複製構造函數中的d.j是未初始化的內存訪問?標準是否保證了初始化的順序?

struct D 
{ 
    int j; 

    D(const D& d) { j = d.j; } 
    D(int i) { j = i; } 
}; 

struct A 
{ 
    D d1, d2; 
    A() : d2(2), d1(d2) {} 
}; 

C++標準的哪一部分討論了數據成員的初始化順序?

+0

相關雖然沒有重複的問題:http://stackoverflow.com/questions/1589950/initializer-list-argument-evaluation-order – 2009-11-21 05:32:49

回答

11

我現在沒有標準的方便,所以我不能引用該部分,但結構或類成員初始化總是發生在聲明的順序。構造函數初始化程序列表中提到成員的順序不相關。

GCC有,警告時的順序是不同的警告-Wreorder

 
     -Wreorder (C++ only) 
      Warn when the order of member initializers given in the code does 
      not match the order in which they must be executed. For instance: 

        struct A { 
        int i; 
        int j; 
        A(): j (0), i (1) { } 
        }; 

      The compiler will rearrange the member initializers for i and j to 
      match the declaration order of the members, emitting a warning to 
      that effect. This warning is enabled by -Wall. 
+5

這樣做的原因是,東西被破壞在他們構建的相反順序。您不能在析構函數之後更改訂單成員遭到破壞,因此構造的訂單*必須*對應。 – GManNickG 2009-11-21 01:36:11

+2

但是,您仍然可以參考以前初始化的成員,如下所述:http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.7 – Jherico 2009-11-21 01:37:21

+1

在這種情況下,常見問題解答非常有用,我認爲;該標準規定「每個基礎和成員初始化後都有一個序列點」(12.6.2/3)。 – 2009-11-21 02:54:34

1

是。一個好的編譯器會警告你將在A::d1後初始化。

6

在您的例子它將失敗:

struct A 
{ 
    D d1, d2;  
    A() : d2(2), d1(d2) {} 
}; 

d1: is initialised first as it is declared first. 
d2: is then initialized. 

結果初始化列表會使用到一個無效的對象(D2)的參考構造D1。

這是使編譯器的警告級別儘可能高的原因之一。
另外強制它報告所有警告爲錯誤。

2

此現象在Meyer's的項目13中解釋/突出顯示Effective C++。它說析構函數必須按照其構造函數的相反順序銷燬元素,因此所有的構造函數都必須以相同的順序初始化元素,因此它們按聲明的順序初始化(而不是初始化列表的順序) 。

11

C++標準(ISO/IEC 14882:2003 12.6.2/5,初始化鹼和成員)表示:

初始化按照下列順序進行:

- 首先,並且僅對於如下所述的大多數派生類的構造函數,虛擬基類將按照它們出現在基類的有向無環圖的深度優先從左到右的遍歷中的順序進行初始化,其中「left-to -right「是派生的 類基類指定中的基類名稱的出現順序R-列表。

- 然後,直接基類應按聲明順序初始化,因爲它們出現在base-specifier-list中(不管mem-initializers的順序如何)。

- 然後,非靜態數據成員應按照它們在類定義中聲明的順序進行初始化(不管mem-initializers的順序如何)。

- 最後,執行構造函數的主體。

項目符號點3保證非靜態數據成員初始化的順序。