Manejo de errores en C++: try/catch y más allá — 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

Introducción al manejo de errores en C++

El manejo de errores es una de las tareas clave en el desarrollo de software confiable en C++. A diferencia de algunos lenguajes (por ejemplo, Python o Java), donde las excepciones son el único mecanismo estándar, C++ proporciona al desarrollador varios enfoques. La estabilidad, el rendimiento y la legibilidad del código dependen de elegir la estrategia correcta. En este artículo, analizaremos la construcción clásica try/catch, las capacidades modernas del estándar C++17/20, así como métodos alternativos de manejo de errores.



1. Enfoque clásico: la construcción try/catch

El mecanismo principal de manejo de excepciones en C++ se basa en tres palabras clave: try, catch y throw. Una excepción es un objeto de cualquier tipo que se "lanza" cuando ocurre un error y se "captura" en el bloque correspondiente.



#include <iostream>#include <stdexcept>

double divide(double a, double b) { if (b == 0) { throw std::runtime_error("¡División por cero!"); } return a / b;}

int main() { try { double result = divide(10, 0); std::cout << "Resultado: " << result << std::endl; } catch (const std::runtime_error& e) { std::cerr << "Error: " << e.what() << std::endl; } catch (...) { std::cerr << "¡Error desconocido!" << std::endl; } return 0;}


Puntos importantes:

  • Jerarquía de excepciones: se recomienda lanzar objetos de clases heredadas de std::exception (por ejemplo, std::runtime_error, std::logic_error).
  • Captura por referencia: siempre capture las excepciones por referencia constante (const std::exception&) para evitar el slicing y copias innecesarias.
  • Manejador universal: catch (...) captura cualquier excepción, pero no da acceso al objeto de error. Úselo solo como último recurso.


2. Enfoques alternativos: códigos de retorno y std::optional

No siempre las excepciones son la mejor opción. En sistemas de alta carga o programación embebida, a menudo se prefieren mecanismos más ligeros.



2.1. Códigos de retorno (error codes)

La función devuelve un número entero o una enumeración que indica éxito o el tipo de error. Este método es simple y eficiente, pero requiere una verificación explícita del resultado.



enum class ErrorCode { Success, DivisionByZero, Overflow };

ErrorCode safe_divide(double a, double b, double& result) { if (b == 0.0) return ErrorCode::DivisionByZero; result = a / b; return ErrorCode::Success;}

int main() { double res; ErrorCode err = safe_divide(10, 0, res); if (err != ErrorCode::Success) { // Manejo del error }}


2.2. std::optional (C++17)

Un contenedor que puede contener un valor o estar vacío. Ideal para situaciones donde el error es la ausencia de un resultado.



#include <optional>

std::optional<double> divide_opt(double a, double b) { if (b == 0.0) return std::nullopt; return a / b;}

int main() { auto result = divide_opt(10, 2); if (result) { std::cout << *result << std::endl; } else { std::cout << "Error de división" << std::endl; }}


3. Capacidades modernas: noexcept y std::expected (C++23)

El estándar C++ continúa evolucionando, ofreciendo herramientas cada vez más expresivas para trabajar con errores.



3.1. Especificación noexcept

La palabra clave noexcept indica que una función no lanza excepciones. Esto ayuda al compilador a optimizar el código y hace que la interfaz sea más clara.



void l                

Blogs

Book Recommendations