Tipuri de excepții
Pe lângă tipul exception, în C++ mai există și alte tipuri de excepții derivate, care pot fi utilizate în diverse situații. Cele mai importante dintre acestea sunt:
- runtime_error: un tip general de excepții care apar în timpul execuției programului
- range_error: excepție care apare atunci când rezultatul obținut depășește intervalul permis
- overflow_error: excepție care apare atunci când rezultatul obținut este mai mare decât limita superioară acceptată
- underflow_error: excepție care apare atunci când rezultatul unui calcul este un număr negativ nepermis (depășește limita inferioară a valorilor acceptate)
- logic_error: excepție care apare din cauza unor erori logice în codul programului
- domain_error: excepție care apare atunci când pentru o anumită valoare transmisă unei funcții nu există un rezultat definit
- invalid_argument: excepție care apare atunci când unei funcții i se transmite un argument invalid
- length_error: excepție care apare atunci când se încearcă crearea unui obiect de dimensiune mai mare decât cea permisă pentru acel tip
- out_of_range: excepție care apare atunci când se încearcă accesarea unor elemente în afara intervalului permis

Tipurile standard de excepții din C++ sunt împărțite în două grupuri, în funcție de clasa de bază: logic_error sau runtime_error. Majoritatea acestor tipuri sunt definite în fișierul antet <stdexcept>.
Tipurile bazate pe logic_error sunt destinate erorilor care pot fi detectate înainte de rularea programului și apar din cauza unei logici incorecte în cod. De exemplu, apelul unei funcții cu unul sau mai mulți parametri nevalizi sau apelul unei funcții membru pentru un obiect aflat într-o stare incompatibilă cu acea funcție. În loc să tratezi aceste excepții, poți verifica explicit validitatea parametrilor sau starea obiectului înainte de apelul funcției.
Celălalt grup, derivat din runtime_error, este destinat erorilor care pot fi detectate doar în timpul execuției. De exemplu, excepțiile derivate din system_error de obicei încorporează erori generate de apeluri ale sistemului de operare, precum eșecul citirii sau scrierii într-un fișier. Accesul la fișiere, ca și orice interacțiune cu hardware-ul, poate da greș în mod neașteptat (de exemplu, defectarea discului, cabluri deconectate, probleme de rețea etc.).
Construcția try...catch poate include mai multe blocuri catch pentru tratarea diferitelor tipuri de excepții. Atunci când apare o excepție, va fi tratată de blocul catch corespunzător tipului excepției aruncate.
Când folosești mai multe blocuri catch, trebuie să le ordonezi astfel încât cele care tratează excepții mai specifice să vină primele, urmate de cele care tratează tipuri mai generale de excepții.
#include <iostream>
class Person
{
public:
Person(std::string name, unsigned age)
{
if(name.length() > 11)
throw std::length_error("Name must be less than 10 chars");
if(!age || age > 110)
throw std::range_error("Age must be between 1 and 110");
this->name = name;
this->age = age;
}
void print() const
{
std::cout << "Name: " << name << "\tAge: " << age << std::endl;
}
private:
std::string name;
unsigned age;
};
void testPerson(std::string name, unsigned age)
{
try
{
Person person{name, age};
person.print();
}
catch (const std::length_error& ex)
{
std::cout << "Length_error: " << ex.what() << std::endl;
}
catch (const std::range_error& ex)
{
std::cout << "Range_error: " << ex.what() << std::endl;
}
catch (const std::exception&)
{
std::cout << "Something wrong"<< std::endl;
}
}
int main()
{
testPerson("Tom", 38); // Name: Tom Age: 38
testPerson("Gai Yulii Cezar", 42); // Length_error: Name must be less than 10 chars
testPerson("Sam", 250); // Range_error: Age must be between 1 and 110
}
Aici este definită o clasă Person, al cărei constructor primește un șir de caractere (nume) și un număr (vârsta) al utilizatorului. Însă datele transmise pot fi invalide. De exemplu, pentru un interval valid al vârstei stabilim limitele între 1 și 110, iar numele nu trebuie să depășească 11 caractere. În constructor sunt verificate aceste valori și, dacă sunt incorecte, se generează diverse excepții:
Person(std::string name, unsigned age)
{
if(name.length() > 11)
throw std::length_error("Name must be less than 10 chars");
if(!age || age > 110)
throw std::range_error("Age must be between 1 and 110");
this->name = name;
this->age = age;
}
Pentru testare este definită funcția testPerson, în care, într-un bloc try, este creat un obiect Person. Construcția try..catch conține trei blocuri catch pentru diferite tipuri de excepții. Ultimul bloc tratează cel mai general tip de excepție, exception. Al doilea tratează excepțiile de tip range_error, care derivă din runtime_error. Iar primul bloc tratează excepțiile de tip length_error, care derivă din logic_error.
catch (const std::length_error& ex)
{
std::cout << "Length_error: " << ex.what() << std::endl;
}
catch (const std::range_error& ex)
{
std::cout << "Range_error: " << ex.what() << std::endl;
}
catch (const std::exception&)
{
std::cout << "Something wrong"<< std::endl;
}
Folosind funcția what() în blocurile catch, obținem informații despre eroare. În acest caz, programul va produce următoarea ieșire în consolă:
Name: Tom Age: 38
Length_error: Name must be less than 10 chars
Range_error: Age must be between 1 and 110