2012-05-23 20 views
22

Si consideri il seguente (semplificato) Situazione:È possibile utilizzare le variabili membro per inizializzare altri membri in un elenco di inizializzazione?

class Foo 
{ 
private: 
    int evenA; 
    int evenB; 
    int evenSum; 
public: 
    Foo(int a, int b) : evenA(a-(a%2)), evenB(b-(b%2)), evenSum(evenA+evenB) 
    { 
    } 
}; 

Quando ho instanciate Foo come questo:

Foo foo(1,3); 

poi evena è 0, è evenB 2, ma sarà evenSum essere inizializzato a 2?

Ho provato questo sulla mia attuale piattaforma (iOS) e sembra funzionare, ma non sono sicuro se questo codice è portatile.

Grazie per il vostro aiuto!

+0

Questo è uno degli angoli pericolosi in C++. – iammilind

+0

Codepad è un ottimo posto per verificare queste cose: http://codepad.org/uFgZpkwN –

+0

@Agent_L: Questo non ti dirà se il codice è portatile. –

risposta

27

Questo è ben definito e portatile, ma è potenzialmente soggetta a errori.

I membri vengono inizializzati nell'ordine in cui sono dichiarati nel corpo della classe, non nell'ordine in cui sono elencati nell'elenco di inizializzazione. Quindi, se si modifica il corpo della classe, questo codice può fallire in modo silenzioso (sebbene molti compilatori lo individueranno ed emetteranno un avviso).


1. Da [class.base.init] nello standard C++ (s):

In un costruttore non delega, procede inizializzazione nel seguente ordine:

  • In primo luogo, e solo per il costruttore della classe più derivata (1.8), le classi di base virtuali vengono inizializzate in l'ordine in cui appaiono in una traversata da sinistra a destra di profondità del grafo aciclico diretto delle classi di base, doveda sinistra a destra”è l'ordine di apparizione delle classi base nella classe derivata base-specificatore-list.
  • Quindi, le classi di base dirette vengono 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 vengono inizializzati nell'ordine in cui sono stati dichiarati nella definizione di classe (di nuovo indipendentemente dall'ordine degli inizializzatori di mem).
  • Infine, viene eseguita l'istruzione composta del corpo del costruttore.

(evidenziazione è mio.)

Questa sezione dello standard passa poi a dare un esempio di utilizzo variabili membro per inizializzare altre variabili membro.

+0

ok quindi se Foo ha una barra di classe base (ereditarietà pubblica non virtuale) e inserisco il costruttore Bars nella lista di inizializzazione, sarà sempre eseguito prima di tutti gli inizializzatori dei membri, anche se lo metto alla fine della lista di inizializzazione? – Pontomedon

+0

@Pontomedon: Sì. I costruttori della classe base vengono sempre invocati per primi (anche se non sono affatto nella lista). –

6

I membri vengono inizializzati nell'ordine in cui sono dichiarati nella definizione della classe. Finché l'elenco di inizializzazione segue questo ordine, dovrebbe essere ok.

0

Questo anche compilato senza errori su g ++ 4.0.3 (6 anni ora).

Sono fiducioso che questo verrà compilato bene su qualsiasi compilatore ragionevolmente recente.

8

Sì, fornire sono già stati costruiti. Basta non dimenticare che l'ordine di costruzione è l'ordine delle dichiarazioni nella definizione di classe , non l'ordine degli inizializzatori nel costruttore . E che in genere il compilatore non ti dirà se usi una variabile prima che sia stata costruita. Nel tuo caso, ad esempio, se si sposta evenSum al primo della classe, si è undefined comportamento (perché la sua inizializzazione usa membri non inizializzate), anche se nel costruttore, si inizializza evenA e evenB lessicalmente prima evenSum.

Problemi correlati