try, catch în C++

Excepții C++98

try marchează codul care poate arunca o excepție, iar blocurile catch prind și tratează excepțiile de un anumit tip.

Sintaxă
try {
    // cod care poate arunca o excepție
} catch (const std::exception& e) {
    // tratarea erorii
} catch (...) {
    // orice altă excepție
}

Ce face try, catch

Când o operație eșuează (fișier lipsă, text care nu e număr, index invalid), codul poate „arunca” o excepție cu throw. Execuția sare imediat la cel mai apropiat bloc catch potrivit, ieșind din funcții dacă e nevoie. Codul care poate eșua se pune în try { ... }.

Blocurile catch sunt verificate în ordine; se execută primul al cărui tip se potrivește. Pune tipurile specifice (std::out_of_range) înaintea celor generale (std::exception), iar catch (...) la final, pentru orice altceva. Prinde întotdeauna prin referință const: catch (const std::exception& e).

Excepțiile standard derivă din std::exception, iar e.what() dă mesajul. Dacă o excepție nu este prinsă nicăieri, programul se oprește cu std::terminate. Obiectele locale sunt distruse corect pe drum (destructorii rulează), de aceea RAII și excepțiile merg împreună.

Exemple

Exemplul 1: Conversie text în număr

std::stoi aruncă std::invalid_argument dacă textul nu începe cu un număr și std::out_of_range dacă numărul e prea mare pentru int.

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

void citeste_varsta(const std::string& text) {
    try {
        int varsta = std::stoi(text);
        std::println("Vârsta: {}", varsta);
    } catch (const std::invalid_argument&) {
        std::println("\"{}\" nu este un număr", text);
    } catch (const std::out_of_range&) {
        std::println("\"{}\" este prea mare", text);
    }
}

int main() {
    citeste_varsta("34");
    citeste_varsta("abc");
    citeste_varsta("99999999999");
}

Rezultat

Vârsta: 34
"abc" nu este un număr
"99999999999" este prea mare

Exemplul 2: Excepția sare peste funcții

vector::at verifică indexul și aruncă std::out_of_range. Excepția trece prin nota_elevului (linia de după at nu se mai execută) și este prinsă în main.

#include <exception>
#include <print>
#include <vector>

int nota_elevului(const std::vector<int>& note, int pozitie) {
    int n = note.at(pozitie);
    std::println("Am găsit nota de pe poziția {}", pozitie);
    return n;
}

int main() {
    std::vector<int> note = {9, 7, 10};
    try {
        std::println("Nota: {}", nota_elevului(note, 1));
        std::println("Nota: {}", nota_elevului(note, 5));
        std::println("nu se ajunge aici");
    } catch (const std::exception& e) {
        std::println("Eroare prinsă în main");
    }
    std::println("Programul continuă");
}

Rezultat

Am găsit nota de pe poziția 1
Nota: 7
Eroare prinsă în main
Programul continuă

Exemplul 3: catch (…) și destructorii pe drum

Excepția aruncată nu este din std::exception, deci o prinde doar catch (...). Înainte de catch, obiectul g este distrus corect.

#include <print>

struct Garda {
    ~Garda() { std::println("resursa a fost eliberată"); }
};

void lucreaza() {
    Garda g;
    throw 42;  // se poate arunca orice tip, dar nu este recomandat
}

int main() {
    try {
        lucreaza();
    } catch (...) {
        std::println("excepție necunoscută prinsă");
    }
}

Rezultat

resursa a fost eliberată
excepție necunoscută prinsă

Greșeli frecvente

  • Prinzi prin valoare: catch (std::exception e). Excepția derivată este „tăiată” la tipul de bază, iar what() poate da alt mesaj; prinde prin const&.
  • Pui catch (const std::exception&) înaintea lui catch (const std::out_of_range&). Primul le prinde pe toate, iar al doilea nu mai ajunge niciodată să ruleze.
  • Folosești excepții pentru situații normale (de exemplu sfârșitul unei liste). Aruncarea este lentă; păstrează excepțiile pentru erori reale.

Comenzi înrudite

  • throw: Aruncă o excepție: oprește execuția normală și trimite eroarea la cel mai apropiat catch potrivit.
  • 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.