una resueltos programacion poo orientada objetos miembros ejercicios ejemplos ejemplo codigo clases clase c++ g++ compiler-warnings

c++ - resueltos - ¿Por qué debo inicializar las variables miembro en el orden en que se declaran?



miembros de una clase en programacion orientada a objetos (5)

Hoy escribí un código y obtuve un extraño error de compilación, que parece deberse a la inicialización de las variables miembro en un orden diferente al que fueron declaradas.

Ejemplo:

class Test { int a; int b; public: Test() : b(1), a(2) { } }; int main() { Test test; return 0; }

Entonces si lo compilo con -Werror -Wall :

$ g++ -Werror -Wall test.cpp test.cpp: In constructor ‘Test::Test()’: test.cpp:3:9: error: ‘Test::b’ will be initialized after [-Werror=reorder] test.cpp:2:9: error: ‘int Test::a’ [-Werror=reorder] test.cpp:6:5: error: when initialized here [-Werror=reorder] cc1plus: all warnings being treated as errors

Me doy cuenta de que -Wall está pidiendo explícitamente a GCC que vaya por encima de las advertencias, pero supongo que hay una razón para todas ellas. Entonces, ¿cómo podría importar el orden de inicialización de las variables miembro?


¿Por qué debo inicializar las variables miembro en el orden en que se declaran?

Los miembros se inicializarán en el mismo orden en que se declaran, ya sea que lo desee o no. La advertencia le indica que el orden que solicita difiere del orden real de ejecución de la inicialización.


Me doy cuenta de que -Wall está pidiendo explícitamente a GCC que vaya por encima de las advertencias, pero supongo que hay una razón para todas ellas.

-La pared es solo el comienzo. Al contrario de lo que implica el nombre, -Wall no habilita todas las advertencias. Hay algunas advertencias que podrían decirse que están "por encima", pero esas son precisamente las advertencias que -Wall no habilita. Siempre uso -Wall más otros.

En cuanto a su queja, como ya han dicho otros, hay una muy buena razón para esta advertencia. El hecho de que especifique un pedido no significa que el compilador utilizará ese orden. El orden que el compilador debe usar según el estándar se basa en la definición de clase.


El motivo es que se inicializan en el orden en que se declaran en su clase, no en el orden en que los inicializa en el constructor y le advierte que no se utilizará el pedido de su constructor.

Esto es para ayudar a prevenir errores donde la inicialización de b depende de a o viceversa.

El motivo de este pedido es porque solo hay un destructor, y tiene que elegir un "orden inverso" para destruir al miembro de la clase. En este caso, la solución más simple fue usar el orden de declaración dentro de la clase para asegurarse de que los atributos siempre se destruyeran en el orden inverso correcto.


En realidad, el compilador siempre inicializa las variables en el orden de declaración, incluso si escribe los inicializadores en un orden diferente. Por lo tanto, si no escribe las inicializaciones en el orden de declaración, el orden de sus inicializadores no se ajusta al orden de inicialización, lo que puede provocar errores sutiles si las inicializaciones dependen unas de otras.

Por ejemplo, considere el código

Test(): b(42), a(b) {}

Esto es un error porque a se inicializa antes de b , pero se ve bien. Si lo escribe en el orden de la declaración (que es el orden de inicialización), el error se vuelve obvio:

Test(): a(b), b(42) {}

Tenga en cuenta que el error también puede ser más sutil que eso; por ejemplo, imagina que a y b son tipos de clase que generan algo en su constructor; luego, con el orden "incorrecto", usted pensaría que la salida de b debería aparecer antes que la de a cuando, en realidad, ocurrirá lo contrario. Si a ''s de salida que aparece primero conducirá a un archivo no válido, eso también es un error, pero no hay manera de que el compilador podría notar el problema si los constructores están en otra unidad de traducción (aparte del hecho de que el compilador no puede saber si reordenamiento es o no es un error). Por lo tanto, es razonable que el compilador simplemente advierta sobre cada instancia de orden no coincidente.


No deberías hacerlo porque disminuye la legibilidad y es potencialmente engañoso.

Si lo hiciste:

Test() : b(1), a(b) {}

parecería que b entonces a , ambos se establecieron en 1 , mientras que en realidad el valor no inicializado de b se usa para inicializar a antes de que b se inicialice en 1 .