Pruebas de integración de TypeScript con Docker: guía completa

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

El arma secreta del depurador: lo que los programadores de C++ pasan por alto

\n\n

¿Alguna vez has escrito algo como i = i++ + ++i; y has obtenido resultados diferentes en distintos compiladores? ¿O has detectado un error extraño que solo se reproducía en el servidor pero no en tu portátil? Conoce el comportamiento indefinido — uno de los enemigos más insidiosos de un desarrollador de C++. Y en el centro de este caos están los puntos de secuencia.

\n\n

En este artículo, desglosaremos qué son los puntos de secuencia, cómo se relacionan con el orden de evaluación en C++, y — lo más importante — cómo evitar pisar estos rastrillos. El material está basado en una pregunta clásica de Stack Overflow que ha acumulado miles de visitas. ¡Vamos allá!

\n\n

¿Qué son los puntos de secuencia?

\n\n

Imagina que eres un director de orquesta. Cada músico (instrucción del procesador) debe entrar en un momento estrictamente definido. Un punto de secuencia es un momento en el tiempo en el que todos los "efectos secundarios" anteriores (cambios de variables, llamadas a funciones) están garantizados de estar completos, y los siguientes aún no han comenzado.

\n\n

En el estándar C++ 98/03, se utilizaba el término punto de secuencia. En C++11, fue reemplazado por las relaciones más estrictas "secuenciado antes / secuenciado después", pero la esencia sigue siendo: entre dos puntos de secuencia, el compilador tiene todo el derecho de reordenar operaciones, siempre que no cambie el resultado (según la regla "as-if").

\n\n

En pocas palabras: si intentas modificar la misma variable dos veces entre dos puntos de secuencia — obtienes comportamiento indefinido. El compilador puede hacer cualquier cosa: desde un resultado correcto hasta formatear tu disco duro (es broma, pero casi cierto).

\n\n

Ejemplos clásicos de puntos de secuencia

\n
    \n
  • El punto y coma ; — final de una expresión
  • \n
  • La coma , como operador (¡pero no en los argumentos de una función!)
  • \n
  • El final de cada expresión en un bucle for (después de la inicialización, condición e incremento)
  • \n
  • Los operadores lógicos && y ||
  • \n
  • El operador ternario ?:
  • \n
  • Una llamada a función (antes de que el cuerpo de la función comience a ejecutarse)
  • \n
\n\n

¿Cómo causan los puntos de secuencia comportamiento indefinido?

\n\n

Aquí hay un ejemplo clásico que todo desarrollador de C++ debería conocer:

\n\n
int i = 0;\ni = i++ + ++i;  // UB! Comportamiento indefinido
\n\n

¿Por qué es UB? Porque entre dos puntos de secuencia (en este caso, entre el inicio y el final de la expresión), la variable i es modificada dos veces:

\n
    \n
  1. El incremento postfijo i++
  2. \n
  3. El incremento prefijo ++i
  4. \n
  5. La asignación i = ...
  6. \n
\n\n

El compilador no sabe en qué orden realizar estas operaciones. ¿El resultado? Un compilador devolverá 2, otro — 3, un tercero — 0. Y en modo de optimización, incluso podría descartar este código por completo.

\n\n

Otro caso complicado: argumentos de función

\n\n
int foo(int a, int b) { return a + b; }\n\nint x = 5;\nint result = foo(++x, ++x);  // UB!
\n\n

Aquí, la coma entre los argumentos no es un operador coma, sino un separador. ¡No hay un punto de secuencia entre la evaluación de los argumentos ++x! Ambos incrementos ocurren "en paralelo" (desde la perspectiva del estándar), y nuevamente obtenemos comportamiento indefinido.

\n\n

Ejemplos prácticos: cómo se ve el UB en código real

\n\n

Ejemplo 1: Un error no obvio con indexación

\n\n
int arr[5] = {0, 10, 20, 30, 40};\nint idx = 1;\narr[idx] = idx++;  // UB!
\n\n

A primera vista, parece simple: queremos escribir 1 en arr[1], y luego incrementar idx. Pero el estándar no garantiza el orden de evaluación del índice idx y el lado derecho idx++. ¿El resultado? Podría escribir en arr[1], o podría escribir en arr[2].

\n\n

Ejemplo 2: Comp

Blogs

Book Recommendations