Tratamento de Erros em C++: try/catch e Técnicas Avançadas

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++: do try/catch às Abordagens Modernas

\n\n

O mecanismo de exceções em C++ é uma ferramenta poderosa, mas que exige profundo entendimento. Enquanto o uso básico de try/catch é conhecido pela maioria dos desenvolvedores, o tratamento profissional de erros envolve muito mais: desde garantias de segurança de exceções até estratégias alternativas sem exceções. Neste artigo, analisaremos técnicas avançadas para lidar com erros no C++ moderno.

\n\n

1. Garantias de Segurança de Exceções: Fundamento do Código Confiável

\n\n

Qualquer função que possa lançar uma exceção deve fornecer uma das três garantias de segurança:

\n\n
    \n
  • Garantia Básica (Basic Guarantee): em caso de exceção, os invariantes do objeto são preservados e não há vazamentos de recursos. O objeto pode estar em um estado imprevisível, mas válido.
  • \n
  • Garantia Forte (Strong Guarantee): a operação é concluída com sucesso ou o estado do programa permanece inalterado (atomicidade). É alcançada através do idiom copy-and-swap.
  • \n
  • Garantia de Ausência de Exceções (Noexcept Guarantee): a função nunca lança exceções. É crucial para destrutores, operações de move e operações usadas em contêineres.
  • \n
\n\n
// Exemplo de garantia forte via copy-and-swap\nclass Vector {\n    int* data;\n    size_t sz, cap;\npublic:\n    void push_back(int value) {\n        if (sz == cap) {\n            // 1. Criamos uma cópia\n            Vector tmp(*this);\n            // 2. Modificamos a cópia (pode lançar exceção)\n            tmp.reserve(cap * 2);\n            // 3. Troca (noexcept!)\n            swap(tmp);\n        }\n        data[sz++] = value;  // noexcept\n    }\n    \n    void swap(Vector& other) noexcept {\n        std::swap(data, other.data);\n        std::swap(sz, other.sz);\n        std::swap(cap, other.cap);\n    }\n};
\n\n

2. RAII como Base do Gerenciamento de Recursos

\n\n

O idiom RAII (Resource Acquisition Is Initialization) não se resume a ponteiros inteligentes. É um princípio fundamental que permite evitar vazamentos de recursos durante exceções:

\n\n
    \n
  • O recurso é adquirido no construtor
  • \n
  • É liberado no destrutor (que por padrão é noexcept)
  • \n
  • Uma exceção no destrutor é UB (comportamento indefinido)
  • \n
\n\n
// Wrapper RAII para descritor de arquivo\nclass FileDescriptor {\n    int fd;\npublic:\n    explicit FileDescriptor(const char* path) \n        : fd(open(path, O_RDONLY)) {\n        if (fd == -1) throw std::runtime_error("Falha ao abrir arquivo");\n    }\n    \n    ~FileDescriptor() noexcept {\n        if (fd != -1) close(fd);\n    }\n    \n    // Proibimos cópia, permitimos move\n    FileDescriptor(FileDescriptor&& other) noexcept : fd(other.fd) {\n        other.fd = -1;\n    }\n};
\n\n

3. Alternativas Modernas às Exceções: std::optional e std::expected

\n\n

Nem todos os erros devem ser tratados com exceções. Para erros esperados (entrada inválida, ausência de dados), é melhor usar tipos wrapper:

\n\n
#include <optional>\n#include <expected>  // C++23\n\n// std::optional — para valores opcionais\nstd::optional<int> safe_divide(int a, int b) {\n    if (b == 0) return std::nullopt;\n    return a / b;\n}\n\n// std::expected — para erros com informação (C++23)\nstd::expected<double, std::string> sqrt_checked(double x) {\n    if (x < 0) return std::unexpected("Entrada negativa");\n    return std::sqrt(x);\n}\n\n// Uso\nauto result = safe_divide(10, 0);\nif (result) {\n    std::cout << *result;\n} else {\n    std::cout << "Divisão por zero";\n}
\n\n

4. noexcept: Especificação e Otimizações

\n\n

O especificador noexcept não é apenas documentação. Ele afeta o desempenho e

Blogs

Book Recommendations