¿Este comportamiento está bien definido?Dependencias en las listas de inicialización
class Foo
{
int A, B;
public:
Foo(int Bar): B(Bar), A(B + 123)
{
}
};
int main()
{
Foo MyFoo(0);
return 0;
}
¿Este comportamiento está bien definido?Dependencias en las listas de inicialización
class Foo
{
int A, B;
public:
Foo(int Bar): B(Bar), A(B + 123)
{
}
};
int main()
{
Foo MyFoo(0);
return 0;
}
No, no está definido. A
se inicializará primero (es el primero en la definición de clase) y utiliza B
sin inicializar.
Los miembros de la clase se inicializan en el orden en que aparecen en la definición de clase, independientemente de su orden en la lista de inicialización. De hecho, es una mala práctica desajustar el orden de definición de miembro con el orden de lista de inicialización.
Si su instancia de Foo
tiene una duración estática, como en Foo f(0); int main(){}
, el comportamiento está bien definido. Los objetos con duración estática se inicializan en cero antes de que tenga lugar cualquier otra inicialización; en ese caso, A
y B
serán 0 cuando se ejecute el constructor. Después de eso, sin embargo, el comportamiento es el mismo: primero A
luego B
, dando A
un valor de 123 y B
un valor de Bar
(todavía feo).
La inicialización se realiza en el orden de aparición en la declaración, no en el orden en que se escribe en el constructor.
mirada a esta pregunta, es algo similar: Initializer list *argument* evaluation order
No, orden de inicialización se define por el orden de la declaración de la clase misma.
Desde el C++ estándar 12.6.2 [class.base.init] p5
:
Inicialización procederá en el siguiente orden:
- En primer lugar, y sólo para el constructor de la clase más derivada como se describe a continuación, las clases base virtuales se inicializan 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" es el orden de aparición de los nombres de clase base en el especificador de base de clase derivado lista.
- Entonces, las clases base directas se inicializarán en orden de declaración tal como aparecen en la lista especificadora base (independientemente del orden de los iniciadores de memoria).
- 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 (de nuevo, independientemente del orden de los iniciadores de memoria).
- Finalmente, se ejecuta el cuerpo del constructor.
[Nota: la orden de declaración es obligatoria para garantizar que los subobjetos base y miembro se destruyan en el orden inverso de inicialización. ]
Indeed. La mejor forma de escribir el constructor sería 'Foo (int Bar): A (Bar + 123), B (Bar) {}'. –
Una nota: gcc (al menos) emite una advertencia si la lista de inicialización no enumera los atributos en el mismo orden en que se declaran en la clase/estructura. –
@Matthieu Sí, pero eso requiere que '-Wextra' esté habilitado. – Maxpm