In questo caso specifico, c’è una differenza tra l’utilizzo di un elenco di inizializzatore dei membri e l’assegnazione di valori in un costruttore?

Internamente e sul codice generato, c’è davvero una differenza tra:

MyClass::MyClass(): _capacity(15), _data(NULL), _len(0) { } 

e

 MyClass::MyClass() { _capacity=15; _data=NULL; _len=0 } 

Grazie…

Supponendo che quei valori siano tipi primitivi, allora no, non c’è differenza. Gli elenchi di inizializzazione fanno la differenza solo quando si hanno oggetti come membri, poiché invece di utilizzare l’inizializzazione predefinita seguita dall’assegnazione, l’elenco di inizializzazione consente di inizializzare l’object al suo valore finale. Questo può effettivamente essere notevolmente più veloce.

È necessario utilizzare l’elenco di inizializzazione per inizializzare membri costanti, riferimenti e class base

Quando è necessario inizializzare membri costanti, riferimenti e parametri pass per costruttori di classi di base, come menzionato nei commenti, è necessario utilizzare l’elenco di inizializzazione.

 struct aa { int i; const int ci; // constant member aa() : i(0) {} // will fail, constant member not initialized }; struct aa { int i; const int ci; aa() : i(0) { ci = 3;} // will fail, ci is constant }; struct aa { int i; const int ci; aa() : i(0), ci(3) {} // works }; 

La class / struct di esempio (non esaustiva) contiene riferimento:

 struct bb {}; struct aa { bb& rb; aa(bb& b ) : rb(b) {} }; // usage: bb b; aa a(b); 

E esempio di inizializzazione della class base che richiede un parametro (ad es. Nessun costruttore predefinito):

 struct bb {}; struct dd { char c; dd(char x) : c(x) {} }; struct aa : dd { bb& rb; aa(bb& b ) : dd('a'), rb(b) {} }; 

Sì. Nel primo caso puoi dichiarare _capacity , _data e _len come costanti:

 class MyClass { private: const int _capacity; const void *_data; const int _len; // ... }; 

Ciò sarebbe importante se si desidera garantire la costanza di queste variabili di istanza durante il calcolo dei loro valori in fase di esecuzione, ad esempio:

 MyClass::MyClass() : _capacity(someMethod()), _data(someOtherMethod()), _len(yetAnotherMethod()) { } 

const istanze const devono essere inizializzate nell’elenco di inizializzazione oppure i tipi sottostanti devono fornire costruttori non parametrici pubblici (quali sono i tipi primitivi).

Aggiungerò che se si hanno membri del tipo di class senza alcun costruttore predefinito, l’inizializzazione è l’unico modo per build la class.

Penso che questo link http://www.cplusplus.com/forum/articles/17820/ dia una spiegazione eccellente, specialmente per quelli nuovi di C ++.

Il motivo per cui gli elenchi di intialiser sono più efficienti è che all’interno del corpo del costruttore vengono eseguiti solo i compiti, non l’inizializzazione. Quindi, se si ha a che fare con un tipo non incorporato, il costruttore predefinito per quell’object è già stato chiamato prima che il corpo del costruttore sia stato inserito. All’interno del corpo del costruttore, stai assegnando un valore a quell’object.

In effetti, si tratta di una chiamata al costruttore predefinito seguito da una chiamata all’operatore di assegnazione delle copie. L’elenco di inizializzazione consente di chiamare direttamente il costruttore di copie e questo a volte può essere notevolmente più veloce (ricorda che l’elenco di inizializzazione è prima del corpo del costruttore)

Una grande differenza è che il compito può inizializzare i membri di una class genitore; l’inizializzatore funziona solo sui membri dichiarati nell’ambito della class corrente.

Dipende dai tipi coinvolti La differenza è simile tra

 std::string a; a = "hai"; 

e

 std::string a("hai"); 

dove il secondo modulo è l’elenco di inizializzazione, cioè fa la differenza se il tipo richiede argomenti del costruttore o è più efficiente con gli argomenti del costruttore.

La vera differenza si riduce a come il compilatore gcc genera il codice macchina e adagia la memoria. Spiegare:

  • (phase1) Prima del corpo di init (inclusa la lista di init): il compilatore alloca la memoria richiesta per la class. La class è già viva!
  • (phase2) Nel corpo di init: poiché la memoria è allocata, ogni assegnazione ora indica un’operazione sulla variabile già in corso / ‘inizializzata’.

Esistono sicuramente altri modi per gestire i membri del tipo const. Ma per facilitare la loro vita, gli scrittori di compilatori gcc decidono di impostare alcune regole

  1. i membri del tipo const devono essere inizializzati prima del corpo di init.
  2. Dopo la fase 1, qualsiasi operazione di scrittura è valida solo per membri non costanti.

C’è solo un modo per inizializzare le istanze della class base e le variabili dei membri non statici e che sta utilizzando l’elenco di inizializzazione.

Se non si specifica una variabile membro di base o non statica nell’elenco di inizializzazione del costruttore, quel membro o base verrà inizializzato di default (se il membro / base è un tipo di class non POD o un array di class non POD tipi) o altrimenti non inizializzati.

Una volta che il corpo del costruttore è entrato, tutte le basi o i membri saranno stati inizializzati o non inizializzati (cioè avranno un valore indeterminato). Non vi è alcuna possibilità nel corpo del costruttore di influenzare il modo in cui dovrebbero essere inizializzati.

Potresti essere in grado di assegnare nuovi valori ai membri nel corpo del costruttore ma non è ansible assegnare a membri const o membri di tipo di class che sono stati resi non assegnabili e non è ansible riassociare i riferimenti.

Per i tipi incorporati e alcuni tipi definiti dall’utente, l’assegnazione nel corpo del costruttore può avere esattamente lo stesso effetto dell’inizializzazione con lo stesso valore nell’elenco di inizializzazione.

Se non si riesce a nominare un membro o base in un elenco di inizializzazione e quell’ quadro è un riferimento, ha un tipo di class senza un costruttore predefinito dichiarato dall’utente accessibile, è const qualificato e ha il tipo POD o è un tipo di class POD o array di class POD tipo contenente un membro qualificato const (direttamente o indirettamente) quindi il programma è mal formato.

Se scrivi un elenco di inizializzazione, fai tutto in un solo passaggio; se non si scrive un elenco di inizializzazione, si eseguono 2 passaggi: uno per la dichiarazione e uno per l’assegnazione del valore.

C’è una differenza tra l’elenco di inizializzazione e l’istruzione di inizializzazione in un costruttore. Prendiamo in considerazione il codice seguente:

 #include  #include  #include  #include  class MyBase { public: MyBase() { std::cout << __FUNCTION__ << std::endl; } }; class MyClass : public MyBase { public: MyClass::MyClass() : _capacity( 15 ), _data( NULL ), _len( 0 ) { std::cout << __FUNCTION__ << std::endl; } private: int _capacity; int* _data; int _len; }; class MyClass2 : public MyBase { public: MyClass2::MyClass2() { std::cout << __FUNCTION__ << std::endl; _capacity = 15; _data = NULL; _len = 0; } private: int _capacity; int* _data; int _len; }; int main() { MyClass c; MyClass2 d; return 0; } 

Quando si utilizza MyClass, tutti i membri verranno inizializzati prima della prima istruzione in un costruttore eseguito.

Tuttavia, quando si utilizza MyClass2, tutti i membri non vengono inizializzati quando viene eseguita la prima istruzione in un costruttore.

Nel caso successivo, potrebbe esserci un problema di regressione quando qualcuno ha aggiunto del codice in un costruttore prima che un determinato membro sia inizializzato.