In versiunile timpurii limbajul C++ utiliza, pentru tratarea erorilor, metodele C traditionale: Prima politica necesita verificarea, de fiecare data, a valorii returnate de functie; constructorii nu returneaza valori, astfel incat ei nu pot utiliza acesta metoda pentru a raporta o eroare!
Headerul C standard <errno.h> defineste un mecanism pentru examinarea si atribuirea de valori unei variabile globale, numite errno, cu rol de semnalizarea a succesului/esecului ultimei operatii. Intr-un mediu cu mai multe fire de executie, codul de eroare ar putea fi modificat de un alt fir de executie inainte ca firul curent sa aiba sansa de a-l examina!
Astfel, ambele politici raporteaza erorile, dar nu garanteaza tratarea lor!

Tratarea exceptiilor a fost adaugata limbajului in anul 1989. Ea reprezinta un mecanism de transfer al codului programului din punctul de aparitie al unei exceptii la un punct de tratare (handler) corespunzator. Acest mecanism consta dintr-un bloc try, o secventa de handlere asociate, o expresie throw si exceptia propriu-zisa (o variabila de tip predefinit sau abstract). De exemplu:


try{
	int *p = new int[1000];
}
catch (std::bad_alloc&){/**/}
catch (std::bad_cast&){/**/}
Handler-ul corespunzator este invocat de o expresie throw dintr-un bloc try (sau dintr-o functie apelata dintr-un bloc try). O expresie throw este similara unei instructiuni return. O expresie throw vida consta din instructiunea throw fara operand si indica un rethrow (daca nici o exceptie nu este tratata, se apeleaza terminate()).

O exceptie poate fi transferata handler-ului prin valoare sau prin referinta. Memoria pentru obiectele de tip exceptie este alocata de o maniera nespecificata; unele implementari utilizeaza o stiva dedicata. Pasarea exceptiei prin referinta asigura comportamentul polimorfic. Pasarea exceptiei prin valoare poate fi costisitoare deoarece obiectul poate fi distrus si reconstituit de cateva ori pana cand este atins handler-ul corespunzator!

Tipul exceptiei determina handler-ul care o va captura si trata. Regulile de potrivire a tipurilor exceptiilor permit doar un set limitat de conversii. Pentru o exceptie E si un handler care captureaza exceptii de tipul T sau T&, potrivirea este valida daca:

O functie care poate genera o exceptie specifica acest lucru in prototipul sau; de exemplu:

class Zerodivide{/**/};
int divide(int, int) throw (Zerodivide);
	//poate genera doar exceptii de tipul Zerodivide!
O functie care NU genereaza exceptii se declara astfel:

bool equals(int, int) throw();
O functie precum

bool equals(int, int);
nu garanteaza nimic in legatura cu exceptiile: poate genera orice tip de exceptie, sau nu va genera exceptii!
O specificare de exceptie nu se poate verifica decat la executie; daca o functie incearca sa genereze o exceptie de un tip nespecificat in prototipul ei, mecanismul de tratare a exceptiilor detecteaza acesta violare si apeleaza functia standard unexpected(). Deoarece o violare a specificarii de exceptie este mai degraba un bug, si nu ar trebui sa se produca, comportamentul implicit al functiei unexpected() este sa apeleze functia terminate(), care termina programul. Acest comportament poate fi modificat cu functia set_unexpected().

C++ aplica o politica prin care limbajul acorda incredere programatorului; astfel, el ignora un cod care pare sa violeze specificatia de exceptie, precum cel din exemplul urmator:


int f(); //f poate genera exceptii de orice tip
void g(int j)throw(){ //g nu genereaza exceptii
	int result = f();
}
Daca f genereaza o exceptie, g va viola garantia de a nu genera exceptii; totusi, acest cod este legal! Desi astfel de situatii pot fi verificate la compilare, verificarea specificatiilor de exceptie se realizeaza numai la executie. Programatorul nu este fortat intr-o situatie de acest gen sa scrie cod try ...catch inutil, deoarece f poate fi, de exemplu, o functie C din biblioteca standard!

C++ solicita concordanta specificarii exceptiilor in clasele derivate: supraincarcarea unei functii virtuale intr-o clasa derivata trebuie sa aiba o specificare de exceptie care este, cel putin, la fel de restrictiva precum specificarea de exceptie a functiei din clasa de baza. De exemplu:


class BaseEx{};
class DerivedEx: public BaseEx{};
class OtherEx{};
class A{
	public:
	virtual void f() throw (BaseEx);
	virtual void g() throw (BaseEx);
	virtual void h() throw (DerivedEx);
	virtual void i() throw (DerivedEx);
	virtual void j() throw (BaseEx);
};
class d: public A{
	public:
	virtual void f() throw (DerivedEx); //ok
	virtual void f() throw (OtherEx);   //error
	virtual void g() throw (DerivedEx); //ok
	virtual void i() throw (BaseEx);    //error
	virtual void j() throw (BaseEx, OtherEx); //error
};
Aceleasi reguli de concordanta se aplica pointerilor la functii: unui pointer la o functie care poseda o specificatie de exceptie i se poate atribui doar o functie care poseda o specificatie de exceptie identica sau mai restrictiva! In consecinta, unui pointer la o functie care nu are specificatie de exceptie nu i se poate atribui o functie care poseda o specificatie de exceptie!
Specificarea de exceptie nu se considera parte a tipului functiei; deci nu se pot declara functii care sa difere numai prin tipul de exceptie generat! De asemenea, declararea unui typedef care contine o specificatie de exceptie este o eroare:

void f(int) throw(Y);
void f(int) throw(Z); //eroare
typedef void (*PF)(int) throw (Exception); //eroare
Generarea unei exceptii dintr-un destructor este o tehnica periculoasa: destructorul poate sa fi fost invocat datorita unei alte exceptii, care determina iesirea obiectului din scop; in acest caz, mecanismul de tratare invoca terminate(). Daca trebuie totusi sa se genereze o exceptie dintr-un destructor, trebuie sa se verifice daca nu cumva este procesata, in mod curent, o exceptie necapturata inca (adica nu s-a intrat inca in handler-ul corespunzator). Se utilizeaza functia standard uncaught_exception() din headerul <stdexcept>:

class FileException{};
File::~File() throw (FileException){
	if (close(file_handler)!=succes){
		if (uncaught_exception() == true) return;
		//este sigur sa se genereze o exceptie
		throw FileException(); //semnalizam eroare
	};
	return; //succes
};
Totusi, un design mai bun trateaza exceptiile in destructor decat sa le lase sa se propage mai departe!

void cleanup() throw(int);
class C{
	public:
	~C();
};
C::~C(){
	try {
		cleanup();
	}
	catch (int){/*tratarea exceptiei */}
}
Pentru un obiect global, constructorul se apeleaza inainte de main(); o exceptie generata de constructor nu poate fi, in acest caz, capturata! Analog, distrugerea unui obiect global se realizeaza dupa terminarea lui main(); o exceptie generata de destructor nu poate fi, in acest caz, capturata!

Limbajul C++ defineste o ierarhie de exceptii standard, derivate din std::exception. Se pot captura astfel aceste exceptii cu un singur catch:


catch(std::exception& ex){
	//trateaza exceptiile de tipul std::exception si pe cele derivate din ea
}