[basic.scope.pdecl] / 1 do rascunho padrão do C ++ 20 teve o seguinte exemplo (não normativo) em uma nota (cotação parcial de antes da mesclagem da solicitação pull 3580 , consulte a resposta a esta pergunta):
unsigned char x = x;
[...] x é inicializado com seu próprio valor (indeterminado).
Isso realmente tem um comportamento bem definido no C ++ 20?
Geralmente, a auto-inicialização do formulário T x = x;
tem um comportamento indefinido em virtude do x
valor de ser indeterminado antes da conclusão da inicialização. A avaliação de valores indeterminados geralmente causa um comportamento indefinido ( [basic.indent] / 2 ), mas há uma exceção específica em [basic.indent] /2.3 que permite inicializar diretamente uma unsigned char
variável de um lvalue unsigned char
com valor indeterminado (causando inicialização com um valor indeterminado) )
Isso, por si só, não causa um comportamento indefinido, mas causaria outros tipos T
que não são tipos de caracteres estreitos não assinados ou std::byte
, por exemplo int x = x;
. Essas considerações aplicadas no C ++ 17 e antes também, consulte também as perguntas vinculadas na parte inferior.
No entanto, mesmo para unsigned char x = x;
, o [basic.lifetime] / 7 do rascunho atual diz:
Da mesma forma, antes que a vida útil de um objeto comece [...] a usar as propriedades do glvalue que não dependem de seu valor, está bem definido. O programa tem comportamento indefinido se:
o glvalue é usado para acessar o objeto, ou
[...]
Isso parece sugerir que x
o valor do exemplo só pode ser usado durante sua vida útil.
[basic.lifetime] / 1 diz:
[...]
A vida útil de um objeto do tipo T começa quando:
- [...] e
- sua inicialização (se houver) está completa (incluindo inicialização vazia) ([dcl.init]),
[...]
Assim x
, a vida útil começa apenas após a inicialização ser concluída. Mas, no exemplo citado x
, o valor é usado antes x
da inicialização da conclusão. Portanto, o uso tem um comportamento indefinido.
Minha análise está correta e, se estiver, afeta casos semelhantes de uso antes da inicialização, como
int x = (x = 1);
quais, até onde eu sei, estavam bem definidas no C ++ 17 e também antes?
Observe que no C ++ 17 (rascunho final) o segundo requisito para o início da vida útil era diferente :
- se o objeto tiver inicialização não-vazia, sua inicialização estará completa,
Como a x
inicialização do C ++ 17 teria uma inicialização vaga (mas não a que está no rascunho atual), sua vida útil já teria começado quando for acessada no inicializador nos exemplos fornecidos acima e, nos dois exemplos, não houve comportamento indefinido devido à vida útil x
em C ++ 17.
A redação anterior ao C ++ 17 é novamente diferente, mas com o mesmo resultado.
A questão não é sobre comportamento indefinido ao usar valores indeterminados, que foram abordados, por exemplo, nas seguintes perguntas:
int x ^= x;
não está sintaticamente bem formado. Você pode ter uma definição de variável com inicializador (ou sejaint x = x;
, UB) ou uma instrução de expressão de atribuição xor (ou sejax ^= x;
, embora seja UB sex
for do tipoint
, foi inicializada por padrão e não foi atribuída anteriormente). Você não pode misturar esses dois em um.Respostas:
Isso foi aberto como uma edição editorial . Foi encaminhado ao CWG para discussão (interna). Aproximadamente 24 horas depois, a pessoa que encaminhou o problema criou uma solicitação pull que modifica o exemplo para deixar claro que esse é o UB:
Esse PR foi adicionado e o problema foi encerrado. Portanto, parece claro que a interpretação óbvia (UB devido ao acesso a um objeto cuja vida útil não foi iniciada) é a interpretação pretendida. Parece que a intenção do comitê é tornar essas construções não funcionais, e o texto não normativo do padrão foi atualizado para refletir isso.
fonte