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ă, iarwhat()poate da alt mesaj; prinde princonst&. - Pui
catch (const std::exception&)înaintea luicatch (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.