2010-10-27 10 views
9

L'ordine di esecuzione nell'elenco di inizializzazione del costruttore è determinabile? So che i membri ordine in una classe è l'ordine in cui vengono inizializzati i membri ma se devo scenario come questo:Ordine di esecuzione nell'elenco di inizializzazione del costruttore

class X() 
{ 
X_Implementation* impl_; 
}; 

and then providing that allocator is available: 

X::X():impl_(Allocate(sizeof(X_Implementation)))//HERE I'M ALLOCATING <--1 
,impl_(Construct<X_Implementation>(impl_))//AND HERE I'M CONSTRUCTING <--2 
{ 
} 

ma perché questo sia affidabile questo ordine deve essere da sinistra a destra. È garantito da GREAT BOOK OF std :: o no? Altrimenti posso sempre spostare la seconda linea nel corpo.

+1

Utilizzare il nuovo inserimento per creare un buffer di memoria precedentemente assegnato. –

+0

Non è possibile inizializzare un oggetto più di una volta, quindi questa domanda è un non sequitur. Oltre a ciò, ovvio duplicato di [Ordine di valutazione elenco di inizializzazione costruttore] (https://stackoverflow.com/questions/1242830/constructor-initialization-list-valutazione-valutazione) –

risposta

28

Secondo le norme ISO/IEC 14882: 2003 (E) Sezione 12.6.2:

inizializzazione procede nel seguente ordine:

  • First , 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 grafico aciclico diretto delle classi di base, dove " da sinistra a destra "i s l'ordine di comparsa dei nomi delle classi di base nell'elenco derivato della classe di base.
  • 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 (di nuovo indipendentemente dall'ordine degli inizializzatori di mem).
  • Infine, viene eseguito il corpo del costruttore.

Quindi, segui questo ordine e avrai il tuo ordine. Inoltre, secondo lo standard, l'ordine è prescritto in modo tale che gli oggetti possano essere non inizializzati nell'ordine inverso con precisione.

22

serie La C++ fa garantire un ordine per le liste di inizializzazione (ISO C++ standard 12.6.2/5):

... membri dati non statici vengono inizializzati nell'ordine in cui sono state dichiarate nel definizione della classe (di nuovo indipendentemente dall'ordine degli inizializzatori di mem ).

(Vedi Wyatt Anderson's answer per ulteriori informazioni.)

Esempio:

class Foo 
{ 
public: 
    Foo(); 
private: 
    A a; 
    B b; 
    C c; 
}; 

Foo::Foo() : b(), a(), c() 
{ 
    // a is initialized first, then b, then c - NOT b, a, then c! 
} 

Tuttavia, non è possibile inizializzare una variabile due volte - quello che hai non verrà compilato.

class X //() what's with the pair of parentheses you have in your code snippet? 
{ 
public: 
    X(); 
private: 
    X_Implementation* impl_; 
}; 

X::X() : 
    impl_(Allocate(sizeof(X_Implementation))), 
    // It is not allowed to initialize a data member twice! 
    impl_(Construct<X_Implementation>(impl_)) 
{ 
} 

Invece, appena messo il lavoro in più nel costruttore:

X::X() : impl_(Allocate(sizeof(X_Implementation))) 
{ 
    impl_ = Construct<X_Implementation>(impl_); 
} 

Ci possono essere problemi di sicurezza eccezione con il codice di cui sopra, ma senza sapere cosa Allocate() o Construct() fa in realtà io' Non sono in grado di dirlo. Vi posso dire che è meglio separare l'allocazione e la costruzione nelle proprie classi se si fa questo, utilizzando il Resource acquisizione è di inizializzazione (Raii) idioma:

class XBase 
{ 
protected: 
    XBase() : impl_(Allocate(sizeof(X_Implementation))) 
    { 
    } 

    ~XBase() 
    { 
     if(impl_ != 0) { Deallocate(impl_); } // Or something like this 
    } 

    X_Implementation* impl_; 
}; 

class X : private XBase // XBase is an implementation detail 
{ 
public: 
    X() 
    { 
     impl_ = Construct<X_Implementation>(impl_); 
    } 

    ~X() 
    { 
     Destruct<X_Implementation>(impl_); // Or something like this 
    } 
}; 

questo modo, se Construct() genera un'eccezione, non si perde memoria poiché verrà chiamato il distruttore della classe base che assegnerà la memoria puntata da impl_. Questo è importante perché se l'eccezione non viene catturata e lascia il costruttore, il relativo distruttore di corrispondenza non verrà chiamato. Vedere Carta di Bjarne Stroustrup sulla sicurezza rispetto alle eccezioni: http://www2.research.att.com/~bs/except.pdf

4

Lo scenario specifico si basa sull'idea di inizializzare lo stesso membro più di una volta. Questo è assolutamente illegale in C++. Il tuo codice non verrà compilato. Quindi, la domanda che stai facendo non esiste davvero.

L'ordine di inizializzazione del membro è l'ordine della relativa dichiarazione nella definizione della classe. In contesti di non ereditarietà che coprono tutto ciò che riguarda l'ordine di inizializzazione nella lista di inizializzazione delle costruzioni.

Problemi correlati