Orden de ejecución en la lista de inicialización del constructor

¿Se puede determinar el orden de ejecución en la lista de inicialización del constructor? Sé que el orden de los miembros en una clase es el orden en el que se inicializarán esos miembros, pero si tengo un escenario como este:

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(impl_))//AND HERE I'M CONSTRUCTING <--2 { } 

pero para que esto sea confiable, 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.

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

La inicialización procederá en el siguiente orden:

  • Primero, y solo para el constructor de la clase más derivada como se describe a continuación, las clases base virtuales 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 “izquierda -to-right “es el orden de aparición de los nombres de las clases base en la clase-especificador-base derivada-clase.
  • Entonces, las clases base directas se inicializarán en orden de statement tal como aparecen en la lista especificadora base (independientemente del orden de los iniciadores de memoria).
  • Luego, los miembros de datos no estáticos se inicializarán en el orden en que se declararon en la definición de la clase (nuevamente, independientemente del orden de los iniciadores de la 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.

El estándar C ++ garantiza un orden para las listas de inicialización (Norma ISO C ++ 12.6.2 / 5):

… los miembros de datos no estáticos se inicializarán en el orden en que se declararon en la definición de la clase (nuevamente, independientemente del orden de los iniciadores de la memoria).

(Consulte la respuesta de Wyatt Anderson 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 puede inicializar una variable dos veces; lo que tiene no se comstackrá.

 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(impl_)) { } 

En cambio, simplemente pon el trabajo extra en el constructor:

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

Puede haber problemas de seguridad de excepción con el código anterior, pero sin saber lo que realmente puedo decir sobre Allocate() o Construct() . Puedo decirles que es mejor separar la asignación y la construcción en sus propias clases si lo hacen, usando la expresión idiomática Adquisición de recursos es inicialización (RAII) :

 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(impl_); } ~X() { Destruct(impl_); // Or something like this } }; 

De esta forma, si Construct() arroja una excepción, no se 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 deja el constructor, no se llamará al destructor correspondiente. Ver el documento de Bjarne Stroustrup sobre seguridad de excepciones: http://www2.research.att.com/~bs/except.pdf

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 comstackrá Entonces, la pregunta que estás haciendo realmente no existe.

El orden de inicialización del miembro es el orden de su statement 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.