Depuración, Pruebas y Optimización de Rendimiento
Describe técnicas comunes de depuración en C++. ¿Cómo abordas un error difícil de reproducir?
Respuesta:
Las técnicas comunes incluyen el uso de un depurador (puntos de interrupción, ejecución paso a paso), registro (logging) y comprobaciones de aserción (assert). Para errores difíciles de reproducir, intentaría reducir el alcance, agregar un registro exhaustivo, usar puntos de interrupción condicionales y considerar técnicas como la bisección o los sanitizadores de memoria (ASan, MSan).
¿Cuál es el propósito de assert() en C++? ¿Cuándo deberías usarlo en lugar de lanzar una excepción?
Respuesta:
assert() se utiliza para depuración para verificar condiciones que siempre deberían ser verdaderas. Si la condición es falsa, termina el programa. Usa assert() para errores de lógica interna que indican un bug, y excepciones para errores de tiempo de ejecución recuperables que el código externo podría manejar.
Explica el concepto de pruebas unitarias (unit testing). ¿Cuáles son algunos frameworks populares de pruebas unitarias en C++?
Respuesta:
Las pruebas unitarias implican probar componentes o funciones individuales de un programa de forma aislada para asegurar que funcionen como se espera. Ayuda a detectar errores temprano y facilita la refactorización. Los frameworks populares de C++ incluyen Google Test (GTest), Catch2 y Boost.Test.
¿Cómo identificas los cuellos de botella de rendimiento en una aplicación C++?
Respuesta:
Utilizaría un perfilador (profiler) (por ejemplo, Callgrind de Valgrind, perf, Google Perftools) para identificar los "puntos calientes" (hot spots) en el código, como funciones que consumen la mayor parte del tiempo de CPU o memoria. Analizar grafos de llamadas y fallos de caché (cache misses) también ayuda a localizar cuellos de botella.
¿Cuál es la diferencia entre una compilación de lanzamiento (release build) y una compilación de depuración (debug build) en C++? ¿Por qué es importante esta distinción para el rendimiento?
Respuesta:
Una compilación de depuración incluye símbolos de depuración y deshabilita las optimizaciones, lo que facilita la depuración pero es más lento. Una compilación de lanzamiento habilita las optimizaciones del compilador y omite los símbolos de depuración, lo que resulta en ejecutables más rápidos y pequeños. Esta distinción es crucial porque las mediciones de rendimiento siempre deben realizarse en compilaciones de lanzamiento.
Nombra algunas técnicas comunes de optimización de rendimiento en C++ a nivel de código.
Respuesta:
Las técnicas incluyen minimizar las asignaciones de memoria, usar std::move para una transferencia eficiente de recursos, optimizar estructuras de datos para la localidad de caché, evitar copias innecesarias, usar la corrección const y aprovechar las optimizaciones del compilador (por ejemplo, desenrollado de bucles, inlining).
¿Qué es la 'Regla de Cero/Tres/Cinco' en C++? ¿Cómo se relaciona con la gestión de recursos y las posibles implicaciones de rendimiento?
Respuesta:
Dicta cómo gestionar los recursos. Regla de Cero: si no hay punteros/recursos brutos, los miembros especiales predeterminados están bien. Regla de Tres/Cinco: si defines un destructor, constructor de copia u operador de asignación de copia, probablemente necesites definir los tres (o cinco, incluyendo constructor/asignación de movimiento). Esto previene fugas de recursos y asegura copias profundas correctas, lo que puede afectar el rendimiento si no se maneja eficientemente (por ejemplo, copias excesivas).
¿Cómo puede la corrección const contribuir a una mejor calidad de código y potencialmente al rendimiento?
Respuesta:
La corrección const ayuda a imponer la inmutabilidad, haciendo que el código sea más seguro y fácil de razonar al prevenir modificaciones accidentales. También permite al compilador realizar optimizaciones más agresivas, ya que sabe que ciertos datos no cambiarán, lo que potencialmente conduce a un mejor rendimiento.
Explica el concepto de 'localidad de caché' (cache locality) y por qué es importante para el rendimiento en C++.
Respuesta:
La localidad de caché se refiere a la organización de los patrones de acceso a datos para maximizar los aciertos de caché (cache hits). Las CPU modernas son mucho más rápidas que la memoria principal, por lo que acceder a datos que ya están en la caché de la CPU es significativamente más rápido. Una buena localidad de caché (temporal y espacial) reduce la latencia de acceso a la memoria, lo que genera mejoras sustanciales de rendimiento.
¿Cuándo usarías un analizador estático (static analyzer) en el desarrollo de C++, y qué beneficios proporciona?
Respuesta:
Usaría un analizador estático (por ejemplo, Clang-Tidy, Cppcheck) de forma temprana y regular en el ciclo de desarrollo. Ayuda a identificar posibles errores, violaciones de estándares de codificación y problemas de diseño sin ejecutar el código, mejorando la calidad del código, la mantenibilidad y previniendo errores en tiempo de ejecución.