2009-10-21 8 views
37

De lo que sé de los beneficios de usar la lista de inicialización es que proporcionan eficacia al inicializar los miembros de la clase que no son integrables. Por ejemplo,Beneficios de las listas de inicialización

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

es preferible,

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

si x es un objeto de una clase personalizada. Aparte de eso, este estilo se utiliza incluso con tipos incorporados en aras de la coherencia.

El beneficio más común de hacer esto es un mejor rendimiento. Si la expresión sea del mismo tipo que la variable miembro x_, el resultado de cualquier expresión se construye directamente dentro de x_ - el compilador no hace una copia separada del objeto.

Con el otro estilo, la expresión cualquiera causa que se cree un objeto temporal por separado, y este objeto temporal se pasa al operador de asignación del objeto x_. Entonces ese objeto temporal es destruido en el; Eso es ineficiente.

Pregunta
¿Hay alguna ganancia de eficiencia en el siguiente ejemplo con la utilización de la lista de inicialización. Creo que no hay ganancia. La primera versión llama al constructor de copia de cadena y al operador de asignación de cadena de otras llamadas (no se crea ninguna temporal). ¿Correcto?

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

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

El otro beneficio de las listas de inicialización (si lo quiere llamar un beneficio) es que son la única forma de inicializar ciertas cosas: clases base utilizando un ctor no predeterminado, miembros de const y miembros de referencia. –

+6

Además, si le preocupa el rendimiento, prefiero usar un 'const &' para pasar el argumento, en lugar de copiar. –

+0

¿Cómo se puede tener 'Fred :: Fred(): x_ (lo que sea)'? Fred no tiene argumentos. –

Respuesta

32

La segunda versión está llamando ctor predeterminado de cadena y luego operador de copia de asignación de cadena - que podría definitivamente (menores) las pérdidas de eficiencia en comparación con el primero, que las llamadas directamente de c copia-ctor (por ejemplo, dependiendo en la implementación de cadenas, puede haber una asignación inútil, y luego liberación de alguna estructura pequeña). ¿Por qué no acaba de utilizar siempre el camino correcto -)

+2

Es cierto. También debe mencionar que, a veces, "la forma correcta" es la opción * solo * que tiene. Si necesita inicializar una referencia o un tipo constante, o algo que no tiene un operador de asignación, no tiene mucha opción en el asunto – jalf

+0

@jalf verdadero, pero no directamente aplicable al código que otorga OP (solo a variantes que usan, por ejemplo, miembros 'string &' en lugar de 'string' ones). –

+0

¿No te refieres a que está llamando al constructor de copias de 'string' y luego a su operador de asignación? –

11

Recuerde que hay una clara diferencia entre un constructor de copia y un operador de asignación:?

  • la ctor copia construye un nuevo objeto utilizando alguna otra instancia como un lugar desde donde obtener información de inicialización.
  • el operador de asignación modifica un objeto ya existente que ya ha sido construido totalmente (incluso si es sólo mediante el uso de un constructor por defecto)

Así que en su segundo ejemplo, un trabajo que ya se ha hecho para crear name por el tiempo que

name=n; 

se alcanza.

Sin embargo, es muy posible (especialmente en este ejemplo) que el trabajo realizado sea infinitamente pequeño (probablemente poniendo a cero algunos miembros de datos en el objeto string) y que el trabajo se optimice completamente en una compilación optimizada. pero se considera buena forma de usar listas de inicializadores siempre que sea posible.

+1

Muy bien dicho. Si bien esto es básico, esto es algo que es muy fácil de pasar por alto/olvidar para alguien como yo que aprendí sobre C y ensamblaje. –

12

Creo que la única manera de inicializar los miembros de datos const se encuentra en la lista de inicialización

Ej.en la cabecera:

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

Y el en el archivo CPP:

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

Es una gran manera de inicializar los miembros que:

  • son const
  • no tienen una constructor predeterminado (es privado)
10

A continuación se presentan los escenarios cuando se usa lista de inicialización:

  1. Para la inicialización de los miembros de datos const no estáticos.
  2. Para la inicialización de los miembros de referencia.
  3. Para la inicialización de objetos miembros que no tienen un constructor predeterminado.
  4. Para la inicialización de miembros de la clase base.
  5. Cuando el nombre del parámetro del constructor es el mismo que el miembro de datos.
  6. Por razones de rendimiento.
+3

La mejor respuesta está aquí – Narek

Cuestiones relacionadas