¿Por qué los miembros de mi estructura no se inicializan correctamente con `{}`?

Tenía el siguiente código:

#include  struct T { int a, b, c; }; int main() { T t = {0}; std::cout << ta << ',' << tb << ',' << tc << '\n'; } 

Salida :

 0,0,0 

Después de muchos años de que este código funcionara felizmente en un entorno de producción crítico, cumpliendo una función vital, los requisitos del proyecto cambiaron y necesitaba que la salida fuera 1,1,1 .

Entonces, cambié {0} a {1} :

 #include  struct T { int a, b, c; }; int main() { T t = {1}; std::cout << ta << ',' << tb << ',' << tc << '\n'; } 

Salida :

 1,0,0 

Esperaba 1,1,1 lugar.

¿Por qué los miembros de mi struct no están siendo inicializados correctamente?

Cuando escribe = {0} , eso solo inicializa explícitamente al primer miembro ; el rest se inicializa en cero implícitamente de acuerdo con el estándar, por lo que a primera vista parece que inicializó explícitamente a todos los miembros con el 0 que escribió, pero no lo hizo .

Ese lugar donde escribió 0 solo afecta al primer miembro. Entonces, cuando, un día, lo cambiaste a 1 pensando que cambiaría a todos los miembros, tendrás un error, como aquí. Es un código engañoso / peligroso / tonto / frágil.

Por esa razón, sin un comentario explicativo que lo acompañe, = {0} no pasará la revisión del código en mi equipo. Originalmente deberías haber escrito:

 T t = {}; 

Y ahora, para resolver su problema de acuerdo con los nuevos requisitos, debe escribir:

 T t = {1,1,1}; 

o, si no le importa que su struct potencialmente pierda POD-ness, otorgue a T un constructor.


Redacción formal

[C++11: 8.5.1/2]: cuando un agregado se inicializa mediante una lista de inicializadores, como se especifica en 8.5.4, los elementos de la lista de inicializadores se toman como inicializadores para los miembros del agregado, en subíndices crecientes o la orden de los miembros Cada miembro se inicializa con copia desde la cláusula de inicializador correspondiente. Si la cláusula initializer es una expresión y se requiere una conversión de reducción (8.5.4) para convertir la expresión, el progtwig está mal formado. [..]

[C++11: 8.5.1/6]: una lista de inicializadores está mal formada si el número de cláusulas de inicializador excede el número de miembros o elementos para inicializar.

[C++11: 8.5.1/7]: si hay menos cláusulas de inicializador en la lista que miembros en el agregado, entonces cada miembro no inicializado explícitamente se inicializará desde una lista de inicializadores vacía (8.5.4) .