O padrão de mandato de um lvalue-para-rvalue conversão da variável ponteiro quando a aplicação de indireção?
-
22-12-2019 - |
Pergunta
TL;DR
Dado o seguinte código:
int* ptr;
*ptr = 0;
não *ptr
necessitam de uma lvalue-para-rvalue conversão de ptr
antes de aplicar o engano?
A norma abrange o tema da lvalue-para-rvalue em muitos lugares, mas não parece especificar informações suficientes para determinar se o * operador de exigir tal conversão.
Detalhes
O lvalue-para-rvalue a conversão é coberto em N3485 na seção 4.1
Lvalue-para-rvalue de conversão parágrafo 1 e diz (ênfase minha vai para a frente):
Um glvalue (3.10) de uma não-função, não do tipo de matriz T pode ser convertido para um prvalue.53 Se T é um tipo incompleto, um programa que necessita esta conversão é mal-formada.Se o objeto ao qual o glvalue refere-se não é um objeto do tipo T, e não é um objeto de uma tipo derivado a partir de T, ou se o objeto não é inicializado, um programa que este necessita de conversão tem comportamento indefinido.[...]
Por isso, não *ptr = 0;
exigem esta conversão?
Se nós vá para a seção 4
parágrafo 1 ele diz:
[...]Um padrão de conversão será aplicado a uma expressão se necessário para convertê-lo para um destino necessário de tipo.
Então, quando é que necessário?Se olharmos para a seção 5
Expressões o lvalue-para-rvalue a conversão é mencionada no parágrafo 9 que diz:
Sempre que um glvalue expressão aparece como um operando do operador que espera um prvalue para que operando, o lvalue-para-rvalue (4.1), matriz-para-ponteiro (4.2), ou função-para-ponteiro (4.3) padrão as conversões são aplicadas para converter a expressão de um prvalue.[...]
e o parágrafo 11 que diz:
Em alguns contextos, uma expressão aparece apenas por seus efeitos colaterais.Tal expressão, é chamado de um descartada-expressão de valor.[...] O lvalue-para-rvalue de conversão (4.1) é aplicada se, e somente se, a a expressão é um lvalue volátil-tipo qualificado e é um dos o seguinte [...]
nem o parágrafo parece aplicar-se a este código de exemplo e 5.3.1
Operadores unários parágrafo 1 ele diz:
O operador unário * operador executa indireção:a expressão que ele é aplicada deve ser um ponteiro para um tipo de objeto, ou um ponteiro para um tipo de função e o resultado é um lvalue referindo-se ao objeto ou função para o qual a expressão de pontos.Se o tipo de expressão é "ponteiro para T," o tipo do resultado é "T". [ Nota:indireção através de um ponteiro para um tipo incompleto (excepto cv void) é válido.O lvalue assim obtido pode ser usado de forma limitada (para inicializar um de referência, por exemplo);este lvalue não deve ser convertido para um prvalue, consulte 4.1.—nota final ]
ele não parece requerer o valor do ponteiro e não vejo qualquer exigências para a conversão do ponteiro aqui eu estou faltando alguma coisa?
Por que isso importa?
Eu vi uma resposta e comentários em outras perguntas que afirmam que o uso de um ponteiro não inicializado é um comportamento indefinido devido a necessidade de um lvalue-para-rvalue conversão de ptr
antes de aplicar o endereçamento indireto.Por exemplo: Onde exatamente padrão de C++ dizer remover a referência de um ponteiro que não foi inicializado é um comportamento indefinido? faz esse argumento, e eu não posso conciliar o argumento com o que é apresentado em qualquer uma das recentes versões de rascunho de padrão.Desde que eu tenho visto isso várias vezes, eu queria ter um esclarecimento.
A prova real de comportamento indefinido não é tão importante, pois como eu disse nos vinculada a pergunta acima, temos outros maneira de obter um comportamento indefinido.
Solução 2
Eu ter convertido a seção atualização na minha pergunta para uma resposta pois neste ponto parece ser a resposta, ainda que uma insatisfatória que a minha pergunta é irrespondível:
dyp indicou-me dois relevantes segmentos que abrangem muito semelhante à terra:
- Qual é o valor da categoria dos operandos em C++, os operadores quando não especificado?
- Faz a inicialização implicar lvalue-para-rvalue conversão?É int x = x;UB?
O consenso parece ser o de que a norma é mal especificado e, portanto, não pode fornecer a resposta que eu estou procurando, José Mansfield postou um relatório de defeitos sobre essa falta de especificação, e parece que é ainda aberto e não está claro quando ele pode ser esclarecida.
Existem alguns argumentos de senso comum para ser feita intenção da norma.Pode-se argumentar Logicially, um operando é um prvalue se a operação requer a utilizar o valor do operando.Outro argumento é que, se olharmos para trás, para o C99 projecto de norma diz um lvalue para rvalue conversão é feita por padrão e as exceções são observadas.A seção relevante do projecto de C99 padrão é 6.3.2.1
Lvalues, matrizes, e a função de designadores parágrafo 2 que diz:
Exceto quando for o operando do operador sizeof, o unário & operador, o operador++, -- o operador ou o operando esquerdo do .o operador ou um operador de atribuição, um lvalue que não tem o tipo de matriz é convertido para o valor armazenado no objeto designado (e não é um lvalue).[...]
o que, basicamente, diz que, com algumas exceções, um operando é convertido para o valor armazenado e desde indireção não é uma exceção se esta é esclarecida também ser o caso em C++ bem, então, seria, de facto, fazer a resposta para a minha pergunta sim.
Como eu tentava esclarecer a prova do comportamento indefinido era menos importante do que esclarecer se um lvalue-para-rvalue a conversão é obrigatória.Se queremos provar comportamento indefinido temos métodos alternativos.Jerry abordagem do senso comum e que indireção requer que a expressão ser um ponteiro para um objeto ou uma função e um valor indeterminado só por acidente aponte para um objeto válido. Em geral, o projeto de C++ padrão não dar uma explícita declaração para dizer usando indeterminado valor é indefinido, ao contrário do C99 projecto de norma Em C++11 e volta a norma não dar uma explícita declaração para dizer usando indeterminado valor é indefinido.Com exceção de iteradores e, por extensão, ponteiros, temos o conceito de valor singular e nos é dito na seção 24.2.1
que:
[...][ Exemplo:Após a declaração de um ponteiro não inicializado x (como int* x;), x deve sempre ser considerado ter um único valor de um ponteiro.exemplo ] [...] Dereferenceable valores são sempre não-singular.
e:
Um erro de iteração é um iterador que pode ser singular.268
e a nota de rodapé 268 diz:
Esta definição aplica-se a ponteiros, desde que os ponteiros são os iteradores.O efeito de remover a referência de um iterador que foi invalidado é indefinido.
Outras dicas
Eu acho que você está se aproximando, ao invés de partir de um ângulo oblíquo, por assim dizer.De acordo com o §5.3.1/1:
Os unários
*
operador executa indireção:a expressão à qual ele é aplicado, deve ser um ponteiro para um tipo de objeto, ou um ponteiro para um tipo de função e o resultado é um lvalue referindo-se ao objeto ou função para que a expressão de pontos.Se o tipo da expressão é "ponteiro para T," o tipo do resultado é "T".
Embora isso não falar sobre o lvalue-para-rvalue conversão, ele requer que a expressão ser um ponteiro para um objeto ou função.Um ponteiro não inicializado não (exceto, talvez por acidente) ser qualquer coisa, de modo que a tentativa de desreferência dá comportamento indefinido.