Tratamento de erros em C++: try, catch e abordagens modernas

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Tratamento de Erros em C++: de try/catch a RAII e noexcept



A confiabilidade de um programa depende diretamente de como ele reage a situações imprevistas. Em C++, o mecanismo principal para isso são as exceções. Neste artigo, vamos analisar a construção clássica try/catch/throw, bem como abordagens alternativas e modernas: RAII, noexcept e tratamento de erros sem exceções.



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



Uma exceção é um objeto que é "lançado" (throw) quando ocorre um erro. O programa pode capturá-lo (catch) e executar ações corretivas sem interromper completamente o funcionamento.



Sintaxe

#include <iostream>#include <stdexcept>

double divide(double a, double b) { if (b == 0.0) { throw std::runtime_error("Divisão por zero!"); } 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 << "Erro: " << e.what() << std::endl; } return 0;}


Regras de Funcionamento

  • throw — cria uma cópia do objeto e transfere o controle para o manipulador.
  • try — bloco de código onde podem ocorrer exceções.
  • catch — captura a exceção por tipo. Vários blocos catch podem ser especificados.
  • Se a exceção não for capturada, std::terminate() é chamado.


Captura pela Classe Base

Todas as exceções padrão herdam de std::exception. Portanto, podemos escrever um manipulador universal:

try {    // código} catch (const std::exception& e) {    std::cerr << "Erro padrão: " << e.what() << std::endl;} catch (...) {    std::cerr << "Exceção desconhecida" << std::endl;}

O bloco catch (...) captura todas as exceções, mas sem acesso ao objeto.



2. Exceções em Construtores e Destrutores



Construtores

Se um construtor lançar uma exceção, o objeto é considerado não criado e o destrutor para ele não é chamado. Isso é importante para o gerenciamento de recursos. Exemplo:

class Resource {public:    Resource() {        std::cout << "Recurso alocado" << std::endl;        throw std::runtime_error("Erro de inicialização");    }    ~Resource() {        std::cout << "Recurso liberado" << std::endl;    }};

int main() { try { Resource r; } catch (...) { std::cout << "Exceção capturada" << std::endl; } // O destrutor de Resource NÃO será chamado! return 0;}


Destrutores

Lançar exceções de um destrutor é uma má prática. Se o destrutor for chamado durante o desenrolamento da pilha (stack unwinding) e lançar uma nova exceção, o programa será encerrado abruptamente. Sempre escreva destrutores como noexcept (por padrão, eles já são).



3. RAII — Gerenciamento Automático de Recursos

O idioma RAII (Resource Acquisition Is Initialization) é a chave para um código seguro. O recurso (memória, arquivo, mutex) é adquirido no construtor e liberado no destrutor. Se ocorrer uma exceção, os destrutores de todos os objetos criados são chamados automaticamente (stack unwinding) e os recursos são liberados.



Exemplo com o smart pointer std::unique_ptr:

#include <memory>#include <iostream>

void process() { auto ptr = std::make_unique<int>(42); // Se uma exceção ocorrer aqui, // unique_ptr liberará a memória automaticamente throw std::runtime_error("Erro em proc");

Blogs

Book Recommendations