Por que os membros da minha estrutura não foram inicializados corretamente usando `{}`?

Eu tinha o seguinte código:

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

Saída :

 0,0,0 

Depois de muitos anos desse código funcionando alegremente em um ambiente de produção crítico, atendendo a uma function vital, os requisitos do projeto mudaram e eu precisava que a saída fosse 1,1,1 .

Então, eu mudei {0} para {1} :

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

Saída :

 1,0,0 

Eu esperava 1,1,1 vez disso.

Por que os membros da minha struct não estão todos sendo inicializados corretamente?

Quando você escreve = {0} , isso apenas inicializa explicitamente o primeiro membro ; o resto é inicializado com zero implicitamente de acordo com o padrão, portanto, parece à primeira vista que você inicializou explicitamente todos os membros com o 0 que você escreveu, mas não o fez .

Aquele lugar onde você escreveu 0 afeta apenas o primeiro membro. Então, quando, um dia, você mudou para 1 pensando que mudaria todos os membros, você teria um bug, como aqui. É um código enganador / perigoso / bobo / frágil.

Por esse motivo, sem um comentário explicativo de acompanhamento, = {0} não passará a revisão de código em minha equipe. Você deveria originalmente ter escrito:

 T t = {}; 

E agora, para resolver seu problema de acordo com os novos requisitos, você deve escrever:

 T t = {1,1,1}; 

ou, se você não se importar com sua struct potencialmente perdendo POD, dê a T um construtor.


Formulação formal

[C++11: 8.5.1/2]: Quando um agregado é inicializado por uma lista de inicializadores, conforme especificado em 8.5.4, os elementos da lista de inicializadores são tomados como inicializadores para os membros do agregado, aumentando o índice ou ordem de membro. Cada membro é inicializado com cópia a partir da cláusula inicializadora correspondente. Se a cláusula inicializadora for uma expressão e uma conversão de restrição (8.5.4) for necessária para converter a expressão, o programa será mal formado. [..]

[C++11: 8.5.1/6]: Uma lista de boot é mal formada se o número de cláusulas do inicializador exceder o número de membros ou elementos a inicializar.

[C++11: 8.5.1/7]: Se houver menos cláusulas de inicializador na lista do que membros no agregado, então cada membro não inicializado explicitamente deve ser inicializado a partir de uma lista de inicializadores vazia (8.5.4) .