2009-11-21 12 views
8

Nel seguente snippet di codice l'inizializzatore di d1 è passato d2 che non è ancora stato costruito (corretto?), Quindi il d.j nel costruttore di copie di D è un accesso di memoria non inizializzato?L'ordine di inizializzazione è garantito dallo standard?

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) {} 
}; 

Quale sezione dello standard C++ discute l'ordine di inizializzazione dei membri dei dati?

+0

Relativo anche se non duplicato domanda: http://stackoverflow.com/questions/1589950/initializer-list-argument-valutazione-ordinazione –

risposta

11

Non ho lo standard a portata di mano in questo momento, quindi non posso citare la sezione, ma l'inizializzazione della struttura o della classe sempre avviene nell'ordine dichiarato. L'ordine in cui i membri sono menzionati nell'elenco di inizializzazione del costruttore non è rilevante.

GCC ha un avvertimento -Wreorder che avvisa quando l'ordine è diverso:

 
     -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

La ragione di questo è che le cose vengono distrutte nell'ordine inverso in cui sono costruite. Non è possibile modificare i membri dell'ordine che vengono distrutti dopo il distruttore, pertanto l'ordine costruito * deve * corrispondere. – GManNickG

+2

Tuttavia, si può ancora fare riferimento a membri precedentemente inizializzati, come discusso qui: http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.7 – Jherico

+1

La spiegazione delle FAQ in questo caso è piuttosto utile, Credo; lo standard dice "c'è un punto di sequenza dopo l'inizializzazione di ogni base e membro" (12.6.2/3). –

1

Sì. Un buon compilatore dovrebbe avvisarti che A::d2 verrà inizializzato dopo A::d1.

6

Nel tuo esempio fallirà:

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

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

Di conseguenza la lista di inizializzazione costruirà d1 utilizzando un riferimento a un oggetto non valido (D2).

Questo è uno dei motivi per aumentare il livello di avviso del compilatore più alto possibile.
E in aggiunta forza forzarlo a segnalare tutti gli avvisi come errori.

2

Questo fenomeno è spiegato/evidenziato nell'elemento 13 di Meyer efficace C++. Dice che il distruttore deve distruggere gli elementi nell'ordine inverso dei suoi costruttori, quindi tutti i costruttori devono inizializzare gli elementi nello stesso ordine, quindi li inizializzano nell'ordine in cui sono dichiarati (invece della sequenza degli elenchi di inizializzazione) .

11

Lo standard C++ (ISO/IEC 14882: 2003 12.6.2/5, inizializzazione basi e membri) dice:

inizializzazione procede nel seguente ordine:

- In primo luogo, e solo per il costruttore della classe più derivata come descritto di seguito, le classi di base virtuali devono essere inizializzate nell'ordine in cui appaiono su una traversata da sinistra a destra di profondità del grafo aciclico diretto delle classi base, dove "left-to -right "è l'ordine di comparsa dei nomi delle classi di base nella classe derivata specifica di base r-list.

- Quindi, le classi di base dirette devono essere inizializzate in ordine di dichiarazione poiché compaiono nell'elenco degli specificatori di base (indipendentemente dall'ordine degli inizializzatori di mem).

- Quindi, i membri di dati non statici devono essere inizializzati nell'ordine in cui sono stati dichiarati nella definizione di classe (sempre indipendentemente dall'ordine degli inizializzatori di mem).

- Infine, viene eseguito il corpo del costruttore.

Il punto di punto 3 garantisce l'ordine di inizializzazione di membri di dati non statici.

Problemi correlati