¿Ha cambiado el estándar de C++ con respecto al uso de valores indeterminados y comportamiento indefinido en C++14?

7 minutos de lectura

¿Ha cambiado el estandar de C con respecto al uso
Shafik Yaghmour

Como se trata en ¿La inicialización implica la conversión de lvalue a rvalue? Es int x = x; UB? el estándar C++ tiene un ejemplo sorprendente en la sección 3.3.2 Punto de declaración en el que un int se inicializa con su propio valor indeterminado:

int x = 12;
{ int x = x; }

Aquí la segunda x se inicializa con su propio valor (indeterminado). — ejemplo final ]

Lo que indica la respuesta de Johannes a esta pregunta es un comportamiento indefinido, ya que requiere una conversión de lvalue a rvalue.

En el último borrador del estándar C++14 N3936 que se puede encontrar aquí este ejemplo ha cambiado a:

unsigned char x = 12;
{ unsigned char x = x; }

Aquí la segunda x se inicializa con su propio valor (indeterminado). — ejemplo final ]

¿Ha cambiado algo en C++14 con respecto a los valores indeterminados y el comportamiento indefinido que ha impulsado este cambio en el ejemplo?

  • Papel relevante: Por qué nada importa: el impacto de la reducción a cero cuando surge la pregunta, ¿por qué no simplemente poner a cero la memoria no inicializada?

    – Shafik Yaghmour

    18 de diciembre de 2017 a las 18:29

  • Si bien el documento es interesante, sus conclusiones no se aplican necesariamente a un lenguaje compilado con anticipación donde los análisis estáticos podrían eliminar la mayor parte o la totalidad del costo.

    – davmac

    19/03/2018 a las 13:30

  • @davmac Este es un ejemplo más práctico. y todos los demás artículos que encontré sobre esto encontraron costos similares. No creo que se haya probado que podamos eliminar este costo, aunque tal vez sea posible.

    – Shafik Yaghmour

    19 de marzo de 2018 a las 16:31

  • Ejemplo que muestra cómo se puede eliminar definitivamente el costo en un caso trivial: godbolt.org/g/Kh9xsp – Estoy de acuerdo en que ciertamente no siempre será posible/práctico eliminar todo el costo, pero ciertamente se ha demostrado que los compiladores pueden eliminar el costo en al menos algunos casos, y no parece haber números difíciles que intenten hacerlo. evalúe el costo promedio/potencial de un compilador AOT optimizado, que es mi punto principal.

    – davmac

    19 de marzo de 2018 a las 16:55

¿Ha cambiado el estandar de C con respecto al uso
Shafik Yaghmour

Sí, este cambio fue impulsado por cambios en el idioma, lo que lo convierte en un comportamiento indefinido. si un valor indeterminado es producido por una evaluación pero con algunas excepciones para caracteres estrechos sin firmar.

Informe de defectos 1787 cuyo texto propuesto se encuentra en N39141 era recientemente aceptado en 2014 y está incorporado en el último borrador de trabajo N3936:

El cambio más interesante con respecto a los valores indeterminados sería la sección 8.5 párrafo 12 que va de:

Si no se especifica un inicializador para un objeto, el objeto se inicializa por defecto; si no se realiza ninguna inicialización, un objeto con duración de almacenamiento automático o dinámico tiene un valor indeterminado. [ Note: Objects with static or thread storage duration are zero-initialized, see 3.6.2. — end note ]

para (énfasis mío):

Si no se especifica ningún inicializador para un objeto, el objeto se inicializa de forma predeterminada. Cuando se obtiene almacenamiento para un objeto con duración de almacenamiento automático o dinámico, el objeto tiene una valor indeterminadoy si no se realiza ninguna inicialización para el objeto, ese objeto retiene un valor indeterminado hasta que se reemplaza ese valor (5.17 [expr.ass]). [Note: Objects with static or thread storage
duration are zero-initialized, see 3.6.2 [basic.start.init]. —nota final] Si una evaluación produce un valor indeterminado, el comportamiento es indefinido excepto en los siguientes casos:

  • Si un valor indeterminado de tipo de carácter estrecho sin signo (3.9.1 [basic.fundamental]) se produce por la evaluación de:

    • el segundo o tercer operando de una expresión condicional (5.16 [expr.cond]),

    • el operando derecho de una coma (5.18 [expr.comma]),

    • el operando de una conversión o conversión a un tipo de carácter estrecho sin signo (4.7 [conv.integral]5.2.3 [expr.type.conv]5.2.9
      [expr.static.cast]5.4 [expr.cast]), o

    • una expresión de valor descartado (Cláusula 5 [expr]),

    entonces el resultado de la operación es un valor indeterminado.

  • Si un valor indeterminado de tipo de carácter estrecho sin signo (3.9.1 [basic.fundamental]) es producido por la evaluación del operando derecho de un operador de asignación simple (5.17 [expr.ass]) cuyo primer operando es un valor l de tipo de carácter estrecho sin signo, un valor indeterminado reemplaza el valor del objeto al que hace referencia el operando izquierdo.

  • Si un valor indeterminado de tipo de carácter estrecho sin signo (3.9.1 [basic.fundamental]) es producido por la evaluación de la expresión de inicialización cuando se inicializa un objeto de tipo de carácter estrecho sin signo, ese objeto se inicializa a un valor indeterminado.

e incluyó el siguiente ejemplo:

[ Example:

int f(bool b) {
  unsigned char c;
  unsigned char d = c; // OK, d has an indeterminate value
  int e = d;           // undefined behavior
  return b ? d : 0;    // undefined behavior if b is true
}

end example ]

Podemos encontrar este texto en N3936 cual es la corriente borrador de trabajo y N3937 es el C++14 DIS.

Antes de C++1y

Es interesante notar que antes de este borrador, a diferencia de C que siempre ha tenido una noción bien especificada de qué usos de los valores indeterminados eran indefinidos C++ usó el término valor indeterminado sin siquiera definirlo (asumiendo que no podemos tomar prestada la definición de C99) y también ver informe de defectos 616. Tuvimos que confiar en la conversión de lvalue a rvalue no especificada que, en borrador del estándar C++11 está cubierto en la sección 4.1 Conversión de valor L a valor R párrafo 1 que dice:

[…]si el objeto no está inicializado, un programa que necesita esta conversión tiene un comportamiento indefinido.[…]


Notas al pie:

  1. 1787 es una revisión de informe de defectos 616podemos encontrar esa información en N3903

  • En mi opinión, es más fácil hacer el formato adecuado con código y citas simplemente escribiéndolo sin espacios y > y luego seleccionando el texto y usando los botones o los atajos (CTRL-K para Kode, CTRL-Q para Citas).

    – mojar

    1 mayo 2014 a las 20:27

  • @user2864740 Para ser específicos, los tipos fundamentales pueden tener trampa representaciones (por ejemplo, señalización NaN) que hacen cosas terribles al programa en ejecución. En C y C++, esto se representa como un tipo de comportamiento indefinido. unsigned char Está prohibido tener una representación trampa, por lo que los nuevos ejemplos tienen un comportamiento definido.

    – Casey

    1 mayo 2014 a las 20:27


  • @Casey: Si bien eso es cierto, no es la razón de ser de esta regla. En particular, todos los tipos integrales sin signo están indirectamente (por las reglas aritméticas del módulo) prohibidos de tener representaciones trampa. Pero solo los tipos de caracteres angostos sin firma se incluyen en esta exención especial.

    – Ben Voigt

    1 mayo 2014 a las 20:36


  • @BenVoigt: Después de una consideración más detallada, creo que al menos un problema teórico puede ser que los compiladores pueden usar cosas como registros de CPU para variables locales o en caché, e incluso tipos que no tendrían ningún relleno si se almacenan en main la memoria puede tener bits de relleno o trampa en otras representaciones legítimas. Aun así, desearía que un comité de estándares formalizara una definición de “comportamiento restringido por implementación” que sería un cruce entre UB y comportamiento definido por implementaciones: se requerirían implementaciones para documentar cuáles podrían ser las consecuencias de algo, y…

    – Super gato

    10 de abril de 2015 a las 14:26


  • … hacer inferencias causales inversas que harían que ignorara cualquier condición que pudiera causar que la variable se leyera sin haber sido inicializada, especialmente si el único “uso” del valor era devolverlo a una cadena de llamadas y finalmente descartarlo eso. Desafortunadamente, no tengo conocimiento de ningún plan para codificar tales cosas; las tendencias parecen ir en la dirección opuesta.

    – Super gato

    10/04/2015 a las 14:35

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad