En primer lugar, algunas definiciones de la norma C++ 03:
1.3.5 comportamiento definido por la implementación
Comportamiento, para una construcción de programa bien formada y corregir los datos, que depende sobre la aplicación y que cada aplicación debe documentar
1.3.12 comportamiento indefinido
Comportamiento, como podría surgir al usar una construcción de programa errónea o datos erróneos, para los cuales esta Norma Internacional no impone requisitos. También se puede esperar un comportamiento indefinido cuando esta Norma Internacional omite la descripción de cualquier definición o comportamiento explícito.
1.3.13 comportamiento no especificado
comportamiento, por una construcción programa bien formada y corregir los datos, que depende de la aplicación. La implementación no es necesaria para documentar qué comportamiento ocurre.
A pesar de que el comportamiento no especificado podría llamarse UB, nunca he visto eso, y UB siempre significa comportamiento indefinido. En toda la norma hay declaraciones similares a "hacer X es un comportamiento indefinido", pero a veces se topa con un caso que simplemente no está cubierto.
Para poner la definición de otra manera, si tiene un comportamiento indefinido en cualquier lugar, entonces todas las apuestas están desactivadas. En lo que respecta al estándar, su programa podría hacer cualquier cosa, desde invitar a su suegra a fin de semana de SuperBowl al running nethack. Debido a la naturaleza de UB, no se puede probar y no se puede esperar ninguna ayuda del compilador. (Aunque para algunos errores triviales, los compiladores generalmente producen diagnósticos.)
Por lo general, algo se define como UB porque simplemente no tiene sentido lógicamente (p.acceder a una matriz fuera de límites), pero también a menudo porque requeriría que la implementación hiciera demasiado trabajo para evitar — a menudo en tiempo de ejecución. Recuerde que C++ se deriva de C, y ser capaz de producir programas altamente optimizados es un objetivo principal de ambos idiomas. Con este fin, los idiomas se remiten al programador para asegurarse de que el código sea correcto en estas situaciones, relacionado con el principio "no pagas por lo que no usas".
Así que, finalmente, UB es malo, muy malo; Evitar a toda costa. Sin embargo, la parte difícil de UB es no saber qué es ni en qué circunstancias ocurre; la parte difícil es reconocer cuando invocas a UB. Por ejemplo:
std::string s = "abc";
char& c = s[0];
cout.write(s.data(), s.length());
c = '-';
Parece perfectamente razonable, ¿no? No, esto es UB, pero funcionará como esperabas en todas las implementaciones populares.
¿Puedes dar un ejemplo de "código que suena por lógica matemática [que] no funciona?" –
La práctica estricta de codificación no es suficiente, a menudo es una interacción inesperada de varias cosas lo que causa UB --- una vez que superas los conceptos básicos, como no usar punteros una vez liberados. –
Entonces, ¿sería correcto suponer que si sigo las especificaciones del lenguaje y no cometí errores al definir lo que quería que el programa hiciera, y no hice nada estúpido, entonces mi programa debería funcionar como se esperaba? –