Manejo de errores en C++: try, catch y enfoques modernos

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
```html

Manejo de errores en C++: de try/catch a RAII y noexcept



La fiabilidad de un programa depende directamente de cómo reacciona ante situaciones imprevistas. En C++, el mecanismo principal para esto son las excepciones. En este artículo, analizaremos la construcción clásica try/catch/throw, así como enfoques alternativos y modernos: RAII, noexcept y el manejo de errores sin excepciones.



1. Mecanismo básico: try, catch, throw



Una excepción es un objeto que se "lanza" (throw) cuando ocurre un error. El programa puede capturarlo (catch) y realizar acciones correctivas sin interrumpir completamente el funcionamiento.



Sintaxis

#include <iostream>#include <stdexcept>

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

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


Reglas de funcionamiento

  • throw — crea una copia del objeto y transfiere el control al manejador.
  • try — bloque de código donde pueden ocurrir excepciones.
  • catch — captura la excepción por tipo. Se pueden especificar múltiples bloques catch.
  • Si la excepción no es capturada, se llama a std::terminate().


Captura por clase base

Todas las excepciones estándar heredan de std::exception. Por lo tanto, se puede escribir un manejador universal:

try {    // código} catch (const std::exception& e) {    std::cerr << "Error estándar: " << e.what() << std::endl;} catch (...) {    std::cerr << "Excepción desconocida" << std::endl;}

El bloque catch (...) captura absolutamente todas las excepciones, pero sin acceso al objeto.



2. Excepciones en constructores y destructores



Constructores

Si un constructor lanza una excepción, se considera que el objeto no ha sido creado y el destructor para él no se llama. Esto es importante para la gestión de recursos. Ejemplo:

class Resource {public:    Resource() {        std::cout << "Recurso asignado" << std::endl;        throw std::runtime_error("Error de inicialización");    }    ~Resource() {        std::cout << "Recurso liberado" << std::endl;    }};

int main() { try { Resource r; } catch (...) { std::cout << "Excepción capturada" << std::endl; } // ¡El destructor de Resource NO será llamado! return 0;}


Destructores

Lanzar excepciones desde un destructor es una mala práctica. Si el destructor se llama durante el desenrollado de la pila (stack unwinding) y lanza una nueva excepción, el programa terminará abruptamente. Siempre escriba los destructores como noexcept (por defecto ya lo son).



3. RAII — gestión automática de recursos

El idiom RAII (Resource Acquisition Is Initialization) es la clave para un código seguro. El recurso (memoria, archivo, mutex) se adquiere en el constructor y se libera en el destructor. Si ocurre una excepción, los destructores de todos los objetos creados se llaman automáticamente (stack unwinding) y los recursos se liberan.



Ejemplo con el puntero inteligente std::unique_ptr:

#include <memory>#include <iostream>

void process() { auto ptr = std::make_unique<int>(42); // Si aquí ocurre una excepción, // unique_ptr liberará la memoria automáticamente throw std::runtime_error("Error en proc"); ```

Blogs

Book Recommendations