¿El estándar ordena una conversión de valor l a valor de la variable de puntero cuando se aplica la indirección?

TL; DR

Dado el siguiente código:

int* ptr; *ptr = 0; 

¿ *ptr requiere una conversión lvalue-a-rvalue de ptr antes de aplicar indirección?

El estándar cubre el tema de lvalue-to-rvalue en muchos lugares, pero no parece especificar suficiente información para determinar si el operador * requiere tal conversión.

Detalles

La conversión de lvalor a rvalue se trata en N3485 en la sección 4.1 Conversión de valor avalor en el párrafo 1 y dice ( énfasis mío en el futuro ):

Un glvalue (3.10) de un tipo T no funcional, no de matriz se puede convertir a un prvalue.53 Si T es un tipo incompleto, un progtwig que necesita esta conversión está mal formado. Si el objeto al que se refiere glvalue no es un objeto de tipo T y no es un objeto de un tipo derivado de T, o si el objeto no está inicializado, un progtwig que necesita esta conversión tiene un comportamiento indefinido . […]

Lo mismo ocurre con *ptr = 0; Necesitar esta conversión ?

Si vamos a la sección 4 párrafo 1 , dice:

[…] Si es necesario , se aplicará una secuencia de conversión estándar para convertirla a un tipo de destino requerido.

Entonces, ¿cuándo es necesario ? Si miramos la sección 5 Expresiones, la conversión lvalor a rvalue se menciona en el párrafo 9 que dice:

Siempre que una expresión glvalue aparece como un operando de un operador que espera un valor pr para ese operando, las conversiones estándar de lvalue-a-rvalue (4.1), de matriz a puntero (4.2) o de función a puntero (4.3) son aplicado para convertir la expresión en un valor pr. […]

y el párrafo 11 que dice:

En algunos contextos, una expresión solo aparece por sus efectos secundarios. Dicha expresión se denomina expresión de valor descartado. […] La conversión lvalue-a-rvalue (4.1) se aplica si y solo si la expresión es un valor l de tipo volátil calificado y es una de las siguientes [ …]

ninguno de los párrafos parece aplicarse a este ejemplo de código y 5.3.1 Operadores unarios párrafo 1 dice:

El operador unario * realiza indirección: la expresión a la que se aplica debe ser un puntero a un tipo de objeto, o un puntero a un tipo de función y el resultado es un valor l que se refiere al objeto o función a la que apunta la expresión. Si el tipo de expresión es “apuntando a T”, el tipo de resultado es “T”. [Nota: la dirección indirecta a través de un puntero a un tipo incompleto (que no sea cv void) es válida. El valor l así obtenido se puede usar de manera limitada (para inicializar una referencia, por ejemplo); este lvalue no se debe convertir a un valor pr, ver 4.1. -Finalizar nota]

no parece requerir el valor del puntero y no veo ningún requisito para una conversión del puntero. ¿Me falta algo?

¿Por qué nos importa?

He visto una respuesta y comentarios en otras preguntas que afirman que el uso de un puntero no inicializado es un comportamiento indefinido debido a la necesidad de una conversión lvalue-r-value de ptr antes de aplicar la indirección. Por ejemplo: ¿Dónde dice exactamente C ++ que desreferenciar un puntero no inicializado es un comportamiento indefinido? hace este argumento y no puedo conciliar el argumento con lo que se establece en cualquiera de los proyectos de versiones recientes de la norma. Como he visto esto varias veces, quería obtener una aclaración.

La prueba real de un comportamiento indefinido no es tan importante ya que como señalé en la pregunta relacionada anteriormente, tenemos otras maneras de llegar a un comportamiento indefinido.

Creo que te estás acercando a esto desde un ángulo bastante oblicuo, por así decirlo. De acuerdo con §5.3.1 / 1:

El operador unario * realiza indirección : la expresión a la que se aplica debe ser un puntero a un tipo de objeto, o un puntero a un tipo de función y el resultado es un valor l que se refiere al objeto o función a la que apunta la expresión. Si el tipo de expresión es “puntero a T”, el tipo de resultado es “T”.

Aunque esto no habla de la conversión lvalue-r-value, requiere que la expresión sea un puntero a un objeto o función. Un puntero no inicializado no será (excepto, quizás por accidente) tal que el bash de desreferenciamiento proporcione un comportamiento indefinido.

He convertido la sección de actualización en mi pregunta en una respuesta ya que en este punto parece ser la respuesta, aunque insatisfactoria, de que mi pregunta no tiene respuesta:

dyp me señaló dos hilos relevantes que cubren un terreno muy similar:

  • ¿Cuál es la categoría de valor de los operandos de los operadores de C ++ cuando no se especifica?
  • ¿La inicialización implica una conversión de valor a validación? Es int x = x; UB?

El consenso parece ser que el estándar está mal especificado y, por lo tanto, no puede proporcionar la respuesta que estoy buscando, Joseph Mansfield publicó un informe de defectos sobre esta falta de especificación , y parece que todavía está abierto y no está claro cuándo puede ser aclarado

Hay algunos argumentos de sentido común que deben hacerse en cuanto a la intención del estándar. Uno puede argumentar Logicially, un operando es un prvalue si la operación requiere usar el valor de ese operando . Otro argumento es que si miramos hacia atrás al C99, el borrador del estándar dice que una conversión de valor a validación se realiza por defecto y se anotan las excepciones. La sección relevante del borrador del estándar C99 es 6.3.2.1 Valores L, matrices y designadores de funciones, párrafo 2, que dice:

Excepto cuando es el operando del operador sizeof, el operador unario, el operador ++, el operador – o el operando izquierdo del. operador o un operador de asignación, un valor l que no tiene tipo de matriz se convierte al valor almacenado en el objeto designado (y ya no es un valor l). […]

que básicamente dice que, con algunas excepciones, un operando se convierte al valor almacenado y dado que la indirección no es una excepción si se aclara que también es así en C ++ , la respuesta a mi pregunta sería .

Cuando traté de aclarar, la prueba de un comportamiento indefinido era menos importante que aclarar si se requiere una conversión de valor a validación. Si queremos demostrar un comportamiento indefinido, tenemos enfoques alternativos. El enfoque de Jerry es de sentido común y en ese direccionamiento indirecto se requiere que la expresión sea un puntero a un objeto o función y un valor indeterminado solo señalará accidentalmente un objeto válido. En general, el borrador del estándar C ++ no da una statement explícita para decir que usar un valor indeterminado no está definido, a diferencia del borrador del estándar C99 En C ++ 11 y el estándar no da una statement explícita para decir que usar un valor indeterminado no está definido. Como la excepción son los iteradores y los punteros de extensión, sí tenemos el concepto de valor singular y en la sección 24.2.1 se nos dice que:

[…] [Ejemplo: después de la statement de un puntero x no inicializado (como con int * x;), siempre se debe asumir que x tiene un valor singular de un puntero. -Final ejemplo] […] Los valores a la derecha siempre son no singulares.

y:

Un iterador no válido es un iterador que puede ser singular. 268

y la nota al pie 268 dice:

Esta definición se aplica a los punteros, ya que los punteros son iteradores. El efecto de desreferenciar un iterador que ha sido invalidado no está definido.

En C ++ 1y, el lenguaje cambia y tenemos una statement explícita que hace que el uso de un valor intermedio no esté definido con algunas excepciones limitadas .