Fácil C++

Divisão segura com exceção

Enunciado

Escreva uma função safe_divide que recebe dois double e retorna a / b. Se b for zero, lance std::invalid_argument com a mensagem "divisao por zero". No main, chame a função com (10, 2) e (5, 0), capturando a exceção e imprimindo a mensagem.

Requisitos

  • A função safe_divide deve lançar std::invalid_argument quando b == 0.
  • O catch deve capturar const std::exception& e imprimir e.what().
  • O programa deve continuar após a exceção e imprimir "Fim".

Código inicial

#include <iostream>
#include <stdexcept>

double safe_divide(double a, double b) {
    // TODO: lance std::invalid_argument se b for zero
    return a / b;
}

int main() {
    // TODO: chame safe_divide e capture exceções
    return 0;
}

Saída esperada

10 / 2 = 5
Erro: divisao por zero
Fim
Ver dica

Use throw std::invalid_argument("divisao por zero"); e no main envolva as chamadas em try { ... } catch (const std::exception& e) { ... }.

Mostrar solução
#include <iostream>
#include <stdexcept>

double safe_divide(double a, double b) {
    if (b == 0.0)
        throw std::invalid_argument("divisao por zero"); // lança exceção
    return a / b;
}

int main() {
    try {
        std::cout << "10 / 2 = " << safe_divide(10, 2) << '\n';
        std::cout << "5 / 0 = " << safe_divide(5, 0) << '\n'; // lança
    } catch (const std::exception& e) {
        std::cout << "Erro: " << e.what() << '\n';
    }
    std::cout << "Fim\n";
    return 0;
}

Passo a passo

  1. Incluímos <stdexcept> para ter acesso a std::invalid_argument.
  2. A função safe_divide verifica se b é zero; se for, lança uma exceção com mensagem descritiva.
  3. No main, a primeira chamada safe_divide(10, 2) ocorre normalmente e imprime 10 / 2 = 5.
  4. A segunda chamada safe_divide(5, 0) lança std::invalid_argument.
  5. O fluxo sai imediatamente do try e entra no catch (const std::exception& e).
  6. Dentro do catch, imprimimos e.what(), que retorna a mensagem "divisao por zero".
  7. Após o catch, a execução continua e imprime Fim.

Por que funciona

O throw interrompe o fluxo normal e procura um catch compatível na pilha de chamadas. Como std::invalid_argument herda de std::exception, o catch por referência captura a exceção sem slicing e permite acessar what(). O programa não aborta porque a exceção foi tratada.

Erros comuns

  • Capturar por valor: catch (std::exception e) causa slicing e perde informações da classe derivada. Use const std::exception&.
  • Esquecer de incluir <stdexcept>: o compilador não conhece std::invalid_argument.
  • Lançar tipo primitivo: throw "divisao por zero"; lança const char*, que não é capturado por std::exception. Prefira classes da biblioteca padrão.
  • Não tratar a exceção: se ninguém capturar, std::terminate é chamado e o programa aborta.

Outra forma de resolver

Poderia capturar especificamente std::invalid_argument:

catch (const std::invalid_argument& e) {
    std::cout << "Erro: " << e.what() << '\n';
}

Isso é útil quando se deseja tratar tipos diferentes de exceção de maneiras distintas.

Saída esperada

10 / 2 = 5
Erro: divisao por zero
Fim