C++: Tratamento de Exceções

Última atualização: 2026-08-26

Quando os programas executam, coisas inesperadas sempre acontecem: arquivos não existem, a memória acaba, a rede se desconecta...

Se não forem tratados, o programa falha.

O tratamento de exceções é o "airbag" do programa — quando ocorrem problemas, ele responde de forma graciosa em vez de falhar abruptamente.


1. Noções Básicas de Tratamento de Exceções

(1) 1.1 O que é uma Exceção?

Uma exceção é um erro ou condição inesperada que ocorre durante a execução do programa.

Exceções Comuns:


(2) 1.2 Os Três Elementos do Tratamento de Exceções

O tratamento de exceções do C++ usa três palavras-chave:

Palavra-chave Função
try Monitorar código que pode lançar erros
catch Capturar e tratar exceções
throw Lançar uma exceção

(3) 1.3 Exemplo Básico

Exemplo: Exceção de Divisão por Zero (Dificuldade ⭐)

▶ Exemplo 1: Exemplo de Código (Dificuldade ⭐)

CPP
#include <iostream>

int divide(int a, int b) {
 if (b == 0) {
 throw "Divisor cannot be 0!"; // Throw exception
 }
 return a / b;
}

int main() {
 try {
 std::cout << divide(10, 2) << std::endl; // Normal
 std::cout << divide(10, 0) << std::endl; // Throws exception
 }
 catch (const char* msg) { // Catch exception
 std::cerr << "Error: " << msg << std::endl;
 }
 
 std::cout << "Program continues running" << std::endl;
 return 0;
}
▶ Experimente

Saída:

TEXT 📖 Somente leitura
5
Error: Divisor cannot be 0!
Program continues running

Resultado da Execução:

TEXT 📖 Somente leitura
5
Error: Divisor cannot be 0!
Program continues running

💡 Dica:



2. Tipos de Exceção

(1) 2.1 Tipos que Podem Ser Lançados

throw pode lançar qualquer tipo:

Tipo Exemplo
Tipos básicos throw 42;
Strings throw "error";
Exceções padrão throw std::runtime_error("error");
Exceções personalizadas throw MyException();

(2) 2.2 Capturando Múltiplas Exceções

Exemplo: Capturando Diferentes Tipos de Exceções (Dificuldade ⭐⭐)

CPP
#include <iostream>
### ▶ Exemplo 2: Exemplo de Código (Dificuldade ⭐)

#include <string>

void process(int value) {
 if (value == 0) {
 throw 0; // Throw int
 }
 if (value < 0) {
 throw std::string("Negative number"); // Throw string
 }
}

int main() {
 try {
 process(-5);
 }
 catch (int e) {
 std::cerr << "Caught int exception: " << e << std::endl;
 }
 catch (const std::string& e) {
 std::cerr << "Caught string exception: " << e << std::endl;
 }
 
 return 0;
}


3. Exceções Padrão

(1) 3.1 Hierarquia std::exception

A biblioteca padrão do C++ define um conjunto de classes de exceção, todas em stdexcept:

TEXT 📖 Somente leitura
std::exception
 ├── std::logic_error
 │ ├── std::invalid_argument
 │ ├── std::out_of_range
 │ └── std::length_error
 └── std::runtime_error
 ├── std::overflow_error
 └── std::underflow_error

(2) 3.2 Exceções Padrão Comuns

Classe de Exceção Descrição
std::invalid_argument Argumento inválido
std::out_of_range Fora dos limites
std::runtime_error Erro em tempo de execução
std::bad_alloc Falha na alocação de memória (new falhou)

Exemplo: Usando Exceções Padrão (Dificuldade ⭐⭐)

CPP
#include <iostream>
#include <stdexcept>
#include <vector>

int main() {
 std::vector<int> v = {1, 2, 3};
 
 try {
 v.at(10); // Out-of-bounds access
 }
 catch (const std::out_of_range& e) {
 std::cerr << "Caught exception: " << e.what() << std::endl;
 }
 
 return 0;
}


4. Exceções Personalizadas

(1) 4.1 Herdando de std::exception

Melhor Prática: Classes de exceção personalizadas devem herdar de std::exception.

Exemplo: Classe de Exceção Personalizada (Dificuldade ⭐⭐⭐)

CPP
#include <iostream>
#include <exception>
#include <string>

// Custom exception class
class MyException : public std::exception {
private:
 std::string msg;
 
public:
 MyException(const std::string& msg) : msg(msg) {}
 
 const char* what() const noexcept override {
 return msg.c_str();
 }
};

int main() {
 try {
 throw MyException("Custom exception");
 }
 catch (const MyException& e) {
 std::cerr << "Caught custom exception: " << e.what() << std::endl;
 }
 
 return 0;
}


5. Segurança de Exceções

(1) 5.1 O que é Segurança de Exceções?

Segurança de exceções significa que mesmo quando uma exceção é lançada, o programa mantém um estado consistente (sem vazamento de recursos, sem corrupção de dados).

Três níveis de garantia:

  1. Garantia básica: O estado do programa é consistente, mas pode ter mudado
  2. Garantia forte: A operação ou tem sucesso ou é completamente revertida (como se nunca tivesse acontecido)
  3. Garantia de não-lançamento: A função nunca lança uma exceção

(2) 5.2 RAII — Uma Ferramenta Poderosa para Gerenciamento de Recursos

RAII (Resource Acquisition Is Initialization): Gerenciar recursos através de objetos, com destrutores liberando-os automaticamente.

Exemplo: Usando Smart Pointers para Segurança de Exceções (Dificuldade ⭐⭐⭐)

CPP
#include <iostream>
#include <memory>

void process() {
 // Use unique_ptr to manage memory; even if an exception is thrown, it will be automatically freed
 std::unique_ptr<int> p(new int(42));
 
 // ... code that may throw exceptions ...
 
 std::cout << *p << std::endl;
} // p is automatically freed

int main() {
 try {
 process();
 }
 catch (...) {
 std::cerr << "Caught exception" << std::endl;
 }
 return 0;
}


6. A Palavra-chave noexcept

(1) 6.1 Uso Básico

O C++11 introduziu noexcept, que declara que uma função não lança exceções.

Exemplo: Declarando Não-Lançamento (Dificuldade ⭐)

TEXT 📖 Somente leitura
void safeFunction() noexcept {
 // This function guarantees not to throw exceptions
}

void unsafeFunction() {
 // May throw exceptions
}

💡 Dica:


❓ Perguntas Frequentes

P: Quando devo usar exceções? R: Para situações verdadeiramente inesperadas, não para fluxo de controle normal.


P: O que é catch(...)? R: Captura todas as exceções, tipicamente usado para limpar recursos antes de relançar.

CPP
try {
 // ...
}
catch (...) {
 // Clean up resources
 throw; // Re-throw
}

P: Construtores podem lançar exceções? R: Sim, mas tenha cuidado com vazamentos de memória. Use smart pointers ou RAII para gerenciar recursos.


▶ Exemplo 3: Capturando Exceções (Dificuldade ⭐)

CPP
#include <iostream>
#include <stdexcept>

double divide(double a, double b) {
    if (b == 0) {
        throw std::runtime_error("Divisor cannot be 0");
    }
    return a / b;
}

int main() {
    try {
        std::cout << divide(10, 2) << std::endl;
        std::cout << divide(10, 0) << std::endl;
    } catch (const std::exception& e) {
        std::cout << "Error: " << e.what() << std::endl;
    }

    return 0;
}
▶ Experimente

Saída:

TEXT 📖 Somente leitura
Error: Divisor cannot be 0
💡 Dica: try-catch captura exceções, throw lança exceções. what() retorna a mensagem de erro.


Conceito Ponto-chave
try-catch-throw Os três elementos do tratamento de exceções
Exceções padrão std::runtime_error, etc.
Exceções personalizadas Herdar de std::exception
Segurança de exceções RAII garante sem vazamento de recursos
noexcept Declara que uma função não lança exceções

📖 Resumo

📝 Exercícios

  1. Básico (Dificuldade ⭐): Escreva uma função de divisão que lança std::runtime_error quando o divisor é 0, e use try/catch em main para capturar e exibir a mensagem de erro.

  2. Intermediário (Dificuldade ⭐⭐): Defina uma classe de exceção personalizada (herdando de std::exception) com dois campos: código de erro e descrição do erro. Após lançá-la, recupere ambos no bloco catch.

  3. Desafio (Dificuldade ⭐⭐⭐): Implemente uma classe "guarda de recursos" que adquire recursos no construtor e os libera no destrutor. Mesmo que uma exceção seja lançada entre eles, os recursos são corretamente liberados (princípio RAII).



Próxima Lição: Operações Avançadas com Arquivos (#41)

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%