Het exceptionsysteem in C++ is gebaseerd op het try-catch mechanisme en het sleutelwoord throw. Bij het optreden van een uitzonderlijke situatie (bijvoorbeeld een resourcefout, schending van een invariant), wordt binnen het try blok een uitzondering geactiveerd via de throw operator. De zoektocht naar de geschikte handler (catch) gebeurt door de stack te doorlopen tot de eerste overeenkomstige type.
Belangrijke details:
std::exception).noexcept specificator geïntroduceerd.Ontwerp:
catch(const std::exception& e).Voorbeeldcode:
#include <iostream> #include <stdexcept> void mayFail(bool fail) { if (fail) throw std::runtime_error("Procesfout"); } int main() { try { mayFail(true); } catch (const std::exception& ex) { std::cout << "Vang exception: " << ex.what() << std::endl; } }
Wat gebeurt er als een uitzondering wordt gegooid vanuit een destructor terwijl een andere uitzondering omhoog wordt doorgegeven in de stack?
Antwoord: Dit zal leiden tot een noodstop van het programma via std::terminate(), omdat het tijdens de afhandeling van een uitzondering niet is toegestaan om een nieuwe uitzondering te genereren (double exception), anders wordt de stack unwinding verstoord.
Voorbeeld:
struct CrashOnDestruct { ~CrashOnDestruct() noexcept(false) { throw std::runtime_error("Fout in destructor!"); } }; void func() { CrashOnDestruct obj; throw std::logic_error("Foutafhandeling"); } int main() { try { func(); } catch (...) { } } // Zal eindigen via std::terminate()
Verhaal
Binnen een grote financiële applicatie werden uitzonderingen gegooid vanuit de destructor van een wrapperklasse voor de database. Een van de belangrijke transacties activeerde een uitzondering bij een fout, en bij het unwinden werd de destructor aangeroepen, die ook een fout gooide. Hele applicatie kwam onverwacht tot stilstand en verloor het werk van de gebruikers. Ontwikkelaars moesten snel de throw in destructors vervangen door logging en correcte afhandeling.
Verhaal
Een microservice behandelde uitzonderingen op de manier: catch(std::exception). Een van de threads gooide uitzonderingen van gebruikersspecifieke types (die niet waren afgeleid van std::exception). Dergelijke fouten werden niet opgevangen, wat leidde tot een onverwachte verbroken verbinding en geheugenlekken.
Verhaal
Het ontbreken van de noexcept specificator in de verplaatsingsmethoden van containers leidde ertoe dat de standaardbibliotheek een langzame kopie gebruikte in plaats van een snelle move-operatie; een significante prestatieverslechtering werd pas aan het licht gebracht tijdens belastingstests.