studio reales proyectos programacion libro introducción incluye herramientas fundamentos fuente español código con avanzado aplicaciones c++ language-lawyer undefined-behavior ctor-initializer

c++ - reales - libro de android studio en español pdf



¿Incrementar en una lista de inicialización de miembro genera un comportamiento indefinido? (2)

¿Esto está causando un comportamiento indefinido? Específicamente, el incremento en la lista de inicializadores y cómo se evaluará.

class Wrinkle { public: Wrinkle(int i) : a(++i), b(++i), x(++i) {} private: int a; int x; int b; };

La diferencia de orden entre la declaración de miembros y la lista de inicializadores es intencional, ya que este es un ejemplo que mostraría exactamente esa diferencia, por lo tanto, ignórelo por ahora.


El estándar C ++ 17 contiene un ejemplo [class.base.init]#7 :

struct B1 { B1(int); /* ... */ }; struct B2 { B2(int); /* ... */ }; struct D : B1, B2 { D(int); B1 b; const int c; }; D::D(int a) : B2(a+1), B1(a+2), c(a+3), b(a+4) { /* ... */ } D d(10);

Esto es seguido por una nota:

[Nota: La inicialización realizada por cada inicializador de mem constituye una expresión completa (4.6). Cualquier expresión en un inicializador de mem se evalúa como parte de la expresión completa que realiza la inicialización. - nota final]

Siguiendo el enlace, la sección 4.6 nos dice que una de las definiciones de "expresión completa" es

... un mem-initializer, incluyendo las expresiones constituyentes del inicializador,

La frase "incluidas las expresiones constituyentes del iniciador" me sugiere enérgicamente que el código anterior es legal, porque los efectos secundarios de ++i se habrán completado antes de pasar al siguiente inicializador. Sin embargo, esta es solo mi lectura de la norma, me complace remitirla a cualquier persona con más experiencia que yo.

(También vale la pena señalar que la inicialización de los miembros se realizará en el orden en que se declaran en la clase, no en el orden en que aparecen en la lista de inicializadores de miembros).


Esto no genera un comportamiento indefinido porque:

[class.base.init]#7

[ Nota: La inicialización realizada por cada inicializador de mem constituye una expresión completa. Cualquier expresión en un inicializador de mem se evalúa como parte de la expresión completa que realiza la inicialización. ]

[intro.execution]

5. Una expresión completa es

  • [...]
  • un declarador de inicio o un inicializador de mem, incluidas las expresiones constituyentes del inicializador,

9. Cada cálculo de valor y efecto secundario asociado con una expresión completa se secuencia antes de cada cálculo de valor y efecto secundario asociado con la siguiente expresión completa a evaluar.

Pero ten cuidado que:

[class.base.init]#13

En un constructor no delegante, la inicialización se realiza en el siguiente orden:

  • [...]

  • Luego, los miembros de datos no estáticos se inicializan en el orden en que fueron declarados en la definición de la clase (de nuevo, independientemente del orden de los inicializadores de memoria).

Por lo tanto, su código asignará efectivamente i + 1 a, i + 2 a x e i + 3 a b .