Vantaggi degli elenchi di inizializzazione

Di quello che so dei vantaggi dell’utilizzo dell’elenco di inizializzazione è che forniscono efficienza quando si inizializzano i membri della class che non sono incorporati. Per esempio,

Fred::Fred() : x_(whatever) { }

è preferibile a

Fred::Fred() { x_ = whatever; }

se x è un object di una class personalizzata. Oltre a questo, questo stile è usato anche con tipi built-in per motivi di coerenza.

Il vantaggio più comune di questo è il miglioramento delle prestazioni. Se l’espressione è dello stesso tipo della variabile membro x, il risultato dell’espressione viene costruito direttamente all’interno di x_ – il compilatore non crea una copia separata dell’object.

Con l’altro stile, l’espressione qualsiasi causa la creazione di un object temporaneo separato e questo object temporaneo viene passato nell’operatore di assegnazione dell’object x_. Quindi quell’object temporaneo viene distrutto al; Questo è inefficiente.

Domanda
C’è un guadagno di efficienza nel seguente esempio con l’uso dell’elenco di inizializzazione. Penso che non ci sia alcun guadagno. La prima versione chiama il costruttore di copie della stringa e l’altro chiama l’operatore di assegnazione della stringa (non c’è alcun temporaneo che sia stato creato). È corretto?

 class MyClass { public: MyClass(string n):name(n) { } private: string name; }; class MyClass { public: MyClass(string n) { name=n; } private: string name; }; 

La seconda versione chiama il ctor predefinito della stringa e quindi l’operatore di assegnazione delle stringhe della stringa – potrebbero esserci perdite di efficienza (minori) rispetto alla prima, che chiama direttamente c-copy-ctor (ad esempio, a seconda dell’implementazione della stringa, potrebbe esserci allocazione inutile-poi-rilascio di qualche piccola struttura). Perché non usare sempre la strada giusta? -)

Penso che l’unico modo per inizializzare i membri dei dati const sia nella lista di inizializzazione

Per esempio. nell’intestazione:

 class C { C(); private: const int x; int y; } 

E nel file cpp:

 C::C() : x( 10 ), y( 10 ) { x = 20; // fails y = 20; } 

È un ottimo modo per inizializzare i membri che:

  • sono const
  • non ho un costruttore predefinito (è privato)

Ricorda che c’è una netta differenza tra un costruttore di copie e un operatore di assegnazione:

  • il copy ctor costruisce un nuovo object usando un’altra istanza come luogo per ottenere informazioni di inizializzazione.
  • l’operatore di assegnazione modifica un object già esistente che è già stato completamente costruito (anche se è solo utilizzando un costruttore predefinito)

Quindi nel tuo secondo esempio, è già stato fatto del lavoro per creare un name nel momento in cui

  name=n; 

è raggiunto.

Tuttavia, è abbastanza ansible (specialmente in questo semplice esempio) che il lavoro svolto sia estremamente piccolo (probabilmente solo azzerando alcuni membri di dati nell’object string ) e che il lavoro sia ottimizzato del tutto in una build ottimizzata. ma è ancora considerato una buona forma usare gli elenchi di inizializzatori quando ansible.

Di seguito sono riportati gli scenari in cui viene utilizzato l’elenco di inizializzazione:

  1. Per l’inizializzazione di membri di dati const non statici.
  2. Per l’inizializzazione dei membri di riferimento.
  3. Per l’inizializzazione di oggetti membro che non hanno un costruttore predefinito.
  4. Per l’inizializzazione dei membri della class base.
  5. Quando il nome del parametro del costruttore è uguale al membro dei dati.
  6. Per motivi di prestazioni.

Possiamo anche eseguire la delega del costruttore tramite l’elenco di inizializzazione.