2009-04-07 17 views
9

¿La lista de inicialización siempre se procesará antes que el código del constructor?¿La lista de inicialización siempre se procesará antes que el código del constructor?

En otras palabras, será el siguiente código siempre imprimir <unknown>, y la clase construida habrá "conocido" por la relación calidad source_ (si la variable global es somethingtrue)?

class Foo { 
    std::string source_; 
public: 
    Foo() : source_("<unknown>") { 
    std::cout << source_ << std::endl; 
    if(something){ 
     source_ = "known"; 
    } 
    } 
}; 

Respuesta

12

Sí, lo hará, según C++11: 12.6.2.

La razón principal para usar init-lists es ayudar al compilador con la optimización. Las listas de inicio para tipos no básicos (es decir, objetos de clase en lugar de int, float, etc.) generalmente se pueden construir in situ.

Si crea el objeto y luego lo asigna en el constructor, esto generalmente genera la creación y destrucción de objetos temporales, lo cual es ineficiente.

Las listas de inicialización pueden evitar esto (si el compilador está a la altura, por supuesto, pero la mayoría deberían hacerlo).

El siguiente programa completo dará como resultado 7 pero esto es para un compilador específico (CygWin g ++) por lo que no garantiza ese comportamiento más que la muestra en la pregunta original.

Sin embargo, según la cita en el primer párrafo anterior, la norma hace realmente lo garantiza.

#include <iostream> 
class Foo { 
    int x; 
    public: 
     Foo(): x(7) { 
      std::cout << x << std::endl; 
     } 
}; 
int main (void) { 
    Foo foo; 
    return 0; 
} 
+0

Me hace preguntarme por qué la gente simplemente no intenta compilar la fuente primero :) – arul

+1

@arul: @dehmann solo puede tener un compilador. Si ese comportamiento está definido por la implementación, la compilación no ayudará. Debería consultar el estándar. – paxdiablo

+1

Sí, solo compilar y probar no dice si funcionará igual en todas partes. – Frank

7

Sí, C++ construye todos los miembros antes de llamar al código de construcción.

7

Como ya se ha respondido, las listas de inicialización se ejecutan por completo antes de ingresando al bloque constructor. Por lo tanto, es completamente seguro usar miembros (inicializados) en el cuerpo constructor.

Ha hecho un comentario en la respuesta aceptada acerca de tener que referirse a los argumentos del constructor, pero no al miembro vars dentro del bloque del constructor. Tu no

Es posible que se confundió con el hecho de que debe referirse a parámetros y no al miembro de atributos dentro la lista de inicialización. Como un ejemplo, dado un X clase que tiene dos miembros (a_ y b_) de tipo int, el siguiente constructor puede ser mal definida:

X::X(int a) : a_(a), b(a_*2) {} 

La posible problema aquí es que la construcción de los elementos de la La lista de inicialización depende del orden de declaración en la clase y no del orden en el que escribe la lista de inicialización. Si la clase se define como:

class X 
{ 
public: 
    X(int a); 
private: 
    int b_; 
    int a_; 
}; 

Entonces, independientemente de cómo se escribe la lista de inicialización, el hecho es que b_ (a_ * 2) será ejecutado antes a_ se inicializa desde la declaración de la miembros es primero b_ y luego a_. Eso creará un error ya que su código cree (y probablemente dependa) en que b_ tiene el doble del valor de a_, y de hecho b_ contiene basura.La solución más simple no está refiriendo a los miembros:

X::X(int a) : a_(a), b(a*2) {} // correct regardless of how X is declared 

evitar este escollo es la razón por la cual se sugiere no utilizar miembro de atributos como parte de la inicialización de otros miembros.

Cuestiones relacionadas