2009-10-21 17 views
37

Di quello che so dei vantaggi dell'utilizzo dell'elenco di inizializzazione è che forniscono efficienza quando si inizializzano i membri della classe che non sono incorporati. Ad esempio,Vantaggi degli elenchi di inizializzazione

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

è preferibile,

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

se x è un oggetto di una classe 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'oggetto.

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

Domanda
C'è un guadagno di efficienza nel seguente esempio con l'utilizzo 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; 
}; 
+17

L'altro vantaggio degli elenchi di inizializzazione (se si desidera chiamarlo un vantaggio) è che sono l'unico modo per inizializzare determinate cose: le classi di base utilizzano un ctor non predefinito, i membri const e i membri di riferimento. –

+6

Inoltre, se sei preoccupato per le prestazioni, preferirei usare un 'const &' per passare l'argomento, invece di copiare. –

+0

Come si può avere 'Fred :: Fred(): x_ (qualunque cosa)'? Fred non accetta argomenti. –

risposta

32

La seconda versione sta chiamando ctor predefinito di stringa e operatore copia assegnazione di stringa - ci potrebbe sicuramente (minore) perdite di efficienza rispetto al primo, che chiama direttamente copia ctor di c (ad esempio, a seconda sull'implementazione della stringa, potrebbe esserci allocazione e rilascio di una piccola struttura inutile. Perché non usare sempre la strada giusta -)

+2

Vero. Dovresti anche menzionare che a volte "la strada giusta" è l'unica * opzione * che hai. Se hai bisogno di inizializzare un riferimento o un tipo const, o qualcosa che non ha un operatore di assegnazione, non hai molta scelta in materia – jalf

+0

@jalf true, ma non direttamente applicabile al codice che l'OP fornisce (solo alle varianti usando ad esempio 'string &' membri invece di 'stringa' quelli). –

+0

Non intendi che sta chiamando il costruttore di copia di 'string', e quindi il suo operatore di assegnazione? –

11

Ricordate che c'è una netta differenza tra un costruttore di copia e un operatore di assegnazione:?

  • ctor copia costruisce un nuovo oggetto utilizzando qualche altro esempio come luogo per ottenere informazioni di inizializzazione da.
  • l'operatore di assegnazione modifica un oggetto già esistente che è già stato completamente costruito (anche se è solo utilizzando un costruttore di default)

Quindi nel tuo secondo esempio, un certo lavoro è già stato fatto per creare name da il tempo che

name=n; 

è raggiunto.

Tuttavia, è molto probabile (soprattutto in questo semplice esempio) che il lavoro svolto è irrisorio (probabilmente solo azzerando alcuni membri di dati nell'oggetto string) e che il lavoro è ottimizzato via del tutto in una build ottimizzata. ma è ancora considerato una buona forma usare gli elenchi di inizializzatori quando possibile.

+1

Molto bene detto. Mentre questo è basilare, questo è qualcosa che è molto facile da trascurare/dimenticare per qualcuno come me che ha imparato su C e sul montaggio. –

12

penso che l'unico modo per inizializzare i dati membro const è nella lista di inizializzazione

Eg.nell'intestazione:

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

E l'nel file cpp:

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

E 'un ottimo modo per inizializzare i membri che:

  • sono const
  • non hanno un costruttore predefinito (è privato)
10

Questi sono gli scenari quando si utilizza lista di inizializzazione:

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

La migliore risposta è qui – Narek

Problemi correlati