El comportamiento indefinido (UB, comportamiento indefinido) es una acción en el código cuyo comportamiento no está definido por el estándar. En tales casos, el compilador es libre de tomar cualquier decisión: el programa puede comportarse de manera diferente en diferentes plataformas, compiladores, o incluso puede desencadenar una guerra nuclear (¡formalmente!). El uso de UB es el error más peligroso en C++.
Ejemplos de UB:
int* p = new int[2]; delete[] p; int x = p[1]; // UB: acceso a memoria después de la liberación
Para prevenir el UB:
¿Qué sucederá con el siguiente código?
int a = 42; int b = a++ + ++a;¿Cuál será el valor de
b?
Respuesta:
Este código provoca UB porque modifica y lee la variable a sin puntos de secuencia (sequence points) entre las operaciones. El estándar no garantiza un resultado específico, y el compilador puede obtener cualquier resultado o incluso generar código inesperado.
Historia En un proyecto del sistema de almacenamiento de datos, uno de los desarrolladores cometió un desbordamiento de array en una función de bajo nivel. El UB solo se manifestaba con ciertos datos del usuario y conducía a la corrupción de la estructura del archivo y pérdida de datos del cliente.
Historia En un proyecto para microcontroladores, se encontraron construcciones que leían variables no inicializadas. Las pruebas pasaron, pero un año después del lanzamiento del dispositivo, surgieron errores aleatorios en la operación, causados por UB: las variables a veces contenían valores basura.
Historia En un gran proyecto de código abierto, se descubrió un descriptor que se liberaba dos veces desde diferentes partes del código. Este UB inicialmente se manifestaba muy raramente, pero en nuevas versiones del SO comenzó a provocar paradas inesperadas frecuentes.