6

C'è qualche vantaggio nel mettere una variabile membro della classe in un elenco inizializzatore che non deve necessariamente trovarsi in un elenco inizializzatore? Esempio:Elenco inizializzatore per oggetti con costruttore predefinito

class Foo 
{ 
public: 
    Foo() {} 
}; 

class Bar 
{ 
public: 
    Bar() : _foo() {} 

private: 
    Foo _foo; 
}; 

Il compilatore fa qualcosa di speciale, in questo caso?

+0

'_foo' è già inizializzare (usando costruttore di default di foo) dalla dichiarazione' Foo _foo; 'Se si vuole ri-inisialize' _foo' usare 'Bar(): _foo (Foo()) {} '. Tuttavia, questo sarebbe inutile. – andre

+4

@ahenderson: non è corretto. '_foo' è inizializzato nella lista di inizializzazione. Questo è l'unico e unico luogo in cui i membri sono inizializzati in una classe. 'Bar(): _foo (Foo()) {}' non * re-initialize * '_foo' - it ** lo inizializza ** it. –

+0

@JohnDibling oh, mi sono sbagliato. Capisco ora dalla lettura della risposta di Kerrek SB. – andre

risposta

7

Un elenco di inizializzazione è il modo preferito per inizializzare i membri in un costruttore. È l'unico modo possibile per inizializzare i membri di riferimento e membri costanti.

anche utilizzando una lista di inizializzazione, si riducono le probabilità di accidentalmente utilizzando la variabile prima è stato inizializzato. Fa parte della più ampia filosofia del mai definire una variabile senza inizializzarla.

+0

Va notato che l'elenco dovrebbe essere nello stesso ordine delle dichiarazioni. È una buona pratica –

+0

I membri di riferimento e costanti possono essere inizializzati utilizzando l'inizializzazione in classe (C++ 11).E per i tipi in questione l'elenco di inizializzazione non ha alcun effetto sulla possibilità di accedere a un membro prima che sia inizializzato; il membro viene inizializzato automaticamente allo stesso tempo in entrambi i casi. – bames53

+3

@EdHeal, è un po 'più che una buona pratica. Sono inizializzati in questo ordine, quindi se si inizializza uno basato su un altro, è meglio mettere quello dipendente dopo quello indipendente nella classe. – chris

1

No, in questo caso non viene fatto nulla di diverso. Non vedo alcun vantaggio nel fare questo.

+0

Il vantaggio è che non confondete le persone che sono state addestrate a cercare gli elenchi di inizializzatori. – Cubic

+2

Non sono sicuro che sia una buona idea soddisfare questo tipo di formazione ... – bames53

6

I membri non menzionati nell'elenco di inizializzazione del costruttore che viene utilizzato sono inizializzati di default. Per Foo ciò significa che verrà chiamato il costruttore predefinito.

La differenza tra Bar() : _foo() { } e non dando Bar un costruttore di default esplicito a tutti (o dire Bar() = default è che la versione non ha un costruttore di default banale. Così i valori della std::is_trivially_constructible<Bar>::value saranno diversi da se hai lasciato la costru ­ tor fuori del tutto, anche se il comportamento è contrario lo stesso.

+1

Direi che la domanda è sulla differenza tra un costruttore fornito dall'utente e senza un inizializzatore nell'elenco di inizializzazione per il membro in questione, non sulla differenza tra un costruttore fornito dall'utente e un costruttore fornito dall'utente. – bames53

9

In questo caso non fa differenza.

ma può essere utile per farlo.
Se si dispone di un gran numero di membri poi avere qualche ma non tutti i membri nella lista possono causare una certa confusione. Inoltre, rafforza nella tua mente l'ordine di inizializzazione (l'ordine è definito dall'ordine di dichiarazione nella classe, ma può essere utile visualizzare questo ordine in classi più grandi dove non tutte le variabili membro sono dichiarate l'una accanto all'altra).

Nota: se li si inserisce nell'ordine errato nella lista internalizer, di solito questo è solo un avvertimento sulla maggior parte dei compilatori (a meno che non si compili con gli avvisi come errori (che si dovrebbe)).

Il vero pericolo è rappresentato dalle classi che dispongono di un membro POD e di un costruttore generato dal compilatore.

class NewFoo 
{ 
     int x; 
     int y; 
}; 
// Version 1: 
class Bar1 
{ 
    NewFoo f; 
}; 
// Version 2: 
class Bar2 
{ 
    NewFoo f; 
    public: 
     Bar2() // f not in list. 
     {} 
}; 
// Version 3: 
class Bar3 
{ 
    NewFoo f; 
    public: 
     Bar3() 
      : f() 
     {} 
}; 

int main() 
{ 
    Bar1  b1a;   // x and y not initialized. 
    Bar1  b1b = Bar1(); // x and y zero initialized. 
    Bar2  b2a;   // x and y not initialized. 
    Bar2  b2b = Bar2(); // x and y not initialized. 
    Bar3  b3a;   // x and y zero initialized. 
    Bar3  b3b = Bar3(); // x and y zero initialized. 
} 
+1

+1 per questa risposta reale. Sto seguendo lo stile che consigli da anni, ma ora mi chiedo se la banale ripetizione dei membri possa anche essere solo "rumore". Per le classi strutturate che hanno solo membri con costruttori predefiniti, non sarebbe meglio usare un elenco di inizializzazione vuoto? – Wolf

+0

@ Wolf: Sì. Questo è tutto contestuale. Dovresti usare la tecnica che rende il codice più facile da leggere. Se è ovvio che la tua classe ha membri costruiti automaticamente, allora va bene solo avere una lista vuota. –

+0

@Wolf: risposta aggiornata con informazioni. –

Problemi correlati