2010-10-27 22 views
9

¿Se puede determinar el orden de ejecución en la lista de inicialización del constructor? Yo sé que los miembros del orden en una clase es el orden en que se inicializan los miembros, pero si tengo escenario como este:Orden de ejecución en la lista de inicialización del constructor

class X() 
{ 
X_Implementation* impl_; 
}; 

and then providing that allocator is available: 

X::X():impl_(Allocate(sizeof(X_Implementation)))//HERE I'M ALLOCATING <--1 
,impl_(Construct<X_Implementation>(impl_))//AND HERE I'M CONSTRUCTING <--2 
{ 
} 

pero para que esto sea fiable esta orden debe ser de izquierda a derecha. ¿Está garantizado por GREAT BOOK OF std :: or not? Si no, siempre puedo mover la segunda línea al cuerpo.

+1

Utilice la ubicación nueva para construir en un búfer de memoria que haya asignado previamente. –

+0

No se puede inicializar un objeto más de una vez, por lo que esta pregunta no es sequitur. Más allá de eso, obvio duplicado de [Constructor initialization-list evaluation order] (https://stackoverflow.com/questions/1242830/constructor-initialization-list-evaluation-order) –

Respuesta

28

De acuerdo con la norma ISO/IEC 14882: 2003 (E) sección 12.6.2:

inicialización procederá en el siguiente orden:

  • Primera y solo para el constructor de la clase más derivada como se describe a continuación, las clases base virtuales serán se inicializarán en el orden en que aparecen en un cruce de profundidad de izquierda a derecha del gráfico acíclico dirigido de clases base, donde " de izquierda a derecha "i s el orden de aparición de los nombres de las clases base en la clase base-especificador-lista derivada.
  • Entonces, las clases de base directas se inicializarán en orden de declaración como aparecen en la base-especificador-list (independientemente del orden de los mem-initializers).
  • A continuación, los miembros de datos no estáticos se inicializarán en el orden en que se declararon en la definición de clase (nuevamente, independientemente del orden de los iniciadores de memoria).
  • Finalmente, se ejecuta el cuerpo del constructor.

Por lo tanto, siga ese orden y tendrá su pedido. También de acuerdo con el estándar, el orden se prescribe como tal para que los objetos puedan ser no inicializados en el orden inverso exacto.

22

estándar de C++ sí garantiza un pedido de listas de inicialización (ISO C++ estándar 12.6.2/5):

... miembros de datos estáticos se inicializan en el orden en que se declaran en el definición de clase (de nuevo, independientemente del orden de los iniciadores de memoria ).

(Ver Wyatt Anderson's answer para obtener más información.)

Ejemplo:

class Foo 
{ 
public: 
    Foo(); 
private: 
    A a; 
    B b; 
    C c; 
}; 

Foo::Foo() : b(), a(), c() 
{ 
    // a is initialized first, then b, then c - NOT b, a, then c! 
} 

Sin embargo, no se puede inicializar una variable dos veces - lo que tiene no se compilará.

class X //() what's with the pair of parentheses you have in your code snippet? 
{ 
public: 
    X(); 
private: 
    X_Implementation* impl_; 
}; 

X::X() : 
    impl_(Allocate(sizeof(X_Implementation))), 
    // It is not allowed to initialize a data member twice! 
    impl_(Construct<X_Implementation>(impl_)) 
{ 
} 

En su lugar, sólo hay que poner el trabajo extra en el constructor:

X::X() : impl_(Allocate(sizeof(X_Implementation))) 
{ 
    impl_ = Construct<X_Implementation>(impl_); 
} 

Puede haber problemas de seguridad excepción con el código anterior, pero sin saber qué Allocate() o Construct() realmente hace que' m no puedo decir. Te puedo decir que es mejor separar la asignación y la construcción en sus propias clases si lo hace, mediante el Recursos adquisición es de inicialización (RAII) idioma:

class XBase 
{ 
protected: 
    XBase() : impl_(Allocate(sizeof(X_Implementation))) 
    { 
    } 

    ~XBase() 
    { 
     if(impl_ != 0) { Deallocate(impl_); } // Or something like this 
    } 

    X_Implementation* impl_; 
}; 

class X : private XBase // XBase is an implementation detail 
{ 
public: 
    X() 
    { 
     impl_ = Construct<X_Implementation>(impl_); 
    } 

    ~X() 
    { 
     Destruct<X_Implementation>(impl_); // Or something like this 
    } 
}; 

esta manera, si Construct() se produce una excepción, no perderá memoria ya que se llamará al destructor de la clase base que desasignará la memoria apuntada por impl_. Esto es importante porque si la excepción no se captura y sale del constructor, su destructor correspondiente no se llamará. Véase el documento de Bjarne Stroustrup en la seguridad excepción: http://www2.research.att.com/~bs/except.pdf

4

Su escenario específico se basa en la idea de inicializar el mismo miembro más de una vez. Esto es completamente ilegal en C++. Tu código no se compilará Entonces, la pregunta que estás haciendo realmente no existe.

El orden de inicialización del miembro es el orden de su declaración en la definición de la clase. En contextos sin herencia que cubre todo lo relacionado con el orden de inicialización en la lista de inicializadores de construcciones.

Cuestiones relacionadas