Storia della questione:
Nel classico C++, i membri di una classe venivano inizializzati solo nella lista di inizializzazione del costruttore. Con C++11 è stata introdotta la possibilità di specificare valori predefiniti direttamente nella dichiarazione all'interno della classe (member initializers) per migliorare la leggibilità e la sicurezza del codice.
Problema:
Esistono diversi modi per assegnare un valore a un membro della classe: direttamente nella dichiarazione (in-class), tramite la lista di inizializzazione del costruttore e già nel corpo del costruttore. I diversi metodi influenzano le prestazioni e la semantica; una comprensione errata porta a copie superflue o distruttori predefiniti, errori con costanti e riferimenti.
Soluzione:
class MyClass { int x = 42; };
class MyClass { const int y; MyClass(int val) : y(val) {} // altrimenti — errore di compilazione };
class MyClass { std::string s; MyClass() { s = "hello"; } // Prima default, poi assegnazione };
Caratteristiche principali:
Quale sarà l'ordine di inizializzazione dei membri: nell'ordine in cui sono dichiarati nella classe o nell'ordine nella lista di inizializzazione?
L'ordine di inizializzazione è sempre quello in cui i membri sono dichiarati nella classe, non nell'ordine della lista di inizializzazione. Violare l'ordine è pericoloso per i membri dipendenti.
class A { int x = 1; int y = 2; A() : y(10), x(20) {} }; // x viene inizializzato prima di y, nonostante l'ordine nella lista
È possibile inizializzare un membro costante all'interno del corpo del costruttore se non è stato inizializzato nella lista?
No. Le costanti vengono inizializzate solo nella lista di inizializzazione. L'assegnazione nel corpo del costruttore è errore di compilazione.
Cosa accade se si assegna un valore predefinito a un membro direttamente nella classe tramite un inizializzatore in classe e lo si sovrascrive nella lista di inizializzazione del costruttore?
Sarà utilizzato il valore dalla lista di inizializzazione del costruttore. Il valore predefinito viene utilizzato solo se la lista non specifica nulla.
class C { int x = 10; C() : x(20) {} // x sarà uguale a 20 };
La classe lavora con un file. Il file è dichiarato come std::ofstream, e viene inizializzato nel corpo del costruttore. Pericolo: con il costruttore predefinito potrebbe essere creato un std::ofstream non valido, portando a errori nel lavoro con il file.
Pro:
Contro:
Il file è inizializzato nella lista di inizializzazione, bloccando un uso errato del file con stato non valido, mentre i membri con dati predefiniti utilizzano l'inizializzatore in classe.
Pro:
Contro: