throw în C++

Excepții C++98

Aruncă o excepție: oprește execuția normală și trimite eroarea la cel mai apropiat catch potrivit.

Sintaxă
throw std::runtime_error("mesaj");
throw;   // în catch: aruncă din nou excepția curentă

Ce face throw

throw expresie; creează un obiect excepție și pornește căutarea unui catch potrivit, urcând prin funcțiile care au apelat-o. Poți arunca orice tip, dar convenția este să arunci obiecte derivate din std::exception: std::runtime_error, std::invalid_argument, std::out_of_range (din <stdexcept>) sau clase proprii derivate din ele.

Într-un bloc catch, throw; fără nimic după aruncă din nou aceeași excepție, mai departe, după ce ai făcut ceva cu ea (de exemplu ai scris-o într-un jurnal).

throw este și o expresie, deci poate apărea într-un operator ternar: return b != 0 ? a / b : throw std::domain_error("împărțire la zero");.

Exemple

Exemplul 1: Validare cu throw

#include <print>
#include <stdexcept>

double retrage(double sold, double suma) {
    if (suma <= 0) {
        throw std::invalid_argument("suma trebuie să fie pozitivă");
    }
    if (suma > sold) {
        throw std::runtime_error("fonduri insuficiente");
    }
    return sold - suma;
}

int main() {
    for (double suma : {100.0, -5.0, 900.0}) {
        try {
            std::println("Sold nou: {}", retrage(500, suma));
        } catch (const std::exception& e) {
            std::println("Eroare: {}", e.what());
        }
    }
}

Rezultat

Sold nou: 400
Eroare: suma trebuie să fie pozitivă
Eroare: fonduri insuficiente

Exemplul 2: Excepție proprie

Clasa derivă din std::runtime_error, deci primește what() și poate fi prinsă ca std::exception; în plus, ține codul produsului.

#include <print>
#include <stdexcept>
#include <string>

class StocEpuizat : public std::runtime_error {
public:
    explicit StocEpuizat(const std::string& cod)
        : std::runtime_error("stoc epuizat pentru " + cod), cod_(cod) {}
    const std::string& cod() const { return cod_; }
private:
    std::string cod_;
};

void comanda(const std::string& cod, int stoc) {
    if (stoc == 0) throw StocEpuizat(cod);
    std::println("Comandă plasată: {}", cod);
}

int main() {
    try {
        comanda("LAP-15", 3);
        comanda("TEL-07", 0);
    } catch (const StocEpuizat& e) {
        std::println("{} (cod: {})", e.what(), e.cod());
    }
}

Rezultat

Comandă plasată: LAP-15
stoc epuizat pentru TEL-07 (cod: TEL-07)

Exemplul 3: Aruncare din nou cu throw;

Funcția notează eroarea și o trimite mai departe, neschimbată; tratarea finală se face în main.

#include <print>
#include <stdexcept>

void proceseaza() {
    try {
        throw std::runtime_error("conexiune pierdută");
    } catch (const std::exception& e) {
        std::println("[jurnal] {}", e.what());
        throw;  // aceeași excepție, mai departe
    }
}

int main() {
    try {
        proceseaza();
    } catch (const std::runtime_error& e) {
        std::println("[main] reîncerc mai târziu: {}", e.what());
    }
}

Rezultat

[jurnal] conexiune pierdută
[main] reîncerc mai târziu: conexiune pierdută

Greșeli frecvente

  • Scrii throw e; în loc de throw; în catch. Se aruncă o copie de tipul declarat în catch, deci o excepție derivată pierde tipul real.
  • Arunci o excepție dintr-un destructor. Dacă destructorul rulează deja din cauza altei excepții, programul se oprește cu std::terminate; în plus, destructorii sunt implicit noexcept.
  • Arunci pointeri (throw new MyError()). Cine prinde trebuie să își amintească să facă delete; aruncă obiecte prin valoare.

Comenzi înrudite

  • try, catch: try marchează codul care poate arunca o excepție, iar blocurile catch prind și tratează excepțiile de un anumit tip.
  • noexcept: Marchează o funcție care promite că nu aruncă excepții; ca operator, verifică la compilare dacă o expresie poate arunca.
  • class: Definește un tip nou care grupează date (membri) și funcțiile care lucrează cu ele (metode); baza programării orientate pe obiecte.
  • std::exception: Clasa de bază a tuturor excepțiilor din biblioteca standard; what() returnează mesajul erorii.
  • std::runtime_error: Excepție pentru erorile care apar doar la rulare, din cauze externe: fișier lipsă, rețea, date greșite.