ProgrammatieC++ systeemprogrammeur

Vertel over de mechanismen voor het omgaan met uitzonderingen (exceptions) in C++. Hoe fouten correct af te handelen en waarom is noexcept nodig?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord.

Historie van de kwestie:

Het mechanisme voor het verwerken van uitzonderingen werd geïntroduceerd in C++ om een betrouwbaardere en gestructureerdere foutafhandeling te waarborgen, in tegenstelling tot foutcodes. Door de jaren heen is de syntaxis uitgebreid en zijn er type-specifiers zoals noexcept toegevoegd voor controle over het annuleren van het gooi van uitzonderingen vanuit functies.

Probleem:

Onjuist omgaan met uitzonderingen leidt vaak tot geheugenlekken, onbepaald gedrag of crashes van toepassingen. Als het gooien van uitzonderingen uit constructors, destructors of bij het werken met bronnen niet wordt overwogen, ontstaat er een serieus probleem met de status van het programma.

Oplossing:

De basis syntaxis - het gebruik van try-catch. Uitzonderingen kunnen van elk type zijn, maar het wordt aanbevolen om gebruikers gedefinieerde uitzonderingen van std::exception te erven. Het sleutelwoord noexcept (C++11+) geeft aan dat een functie geen uitzonderingen mag gooien; het gooien van een uitzondering vanuit een noexcept-functie roept std::terminate() aan.

Voorbeeldcode:

#include <iostream> #include <stdexcept> void func() noexcept(false) { throw std::runtime_error("Error!"); } int main() { try { func(); } catch(const std::exception& ex) { std::cout << ex.what(); } }

Belangrijke kenmerken:

  • Uitzonderingen zorgen voor automatische unwind (stack uitpakken)
  • noexcept stelt de compiler in staat om te optimaliseren als de functie gegarandeerd geen uitzonderingen gooit
  • Alleen std::exception en zijn afgeleiden garanderen de aanwezigheid van de methode what()

Vragen met een valstrik.

Is het toegestaan om uitzonderingen te gooien in een destructor?

Nee, het gooien van een uitzondering uit een destructor tijdens stack unwind leidt tot std::terminate(). Uitzonderingen in de destructor moeten binnen de destructor zelf worden opgevangen.

Wat gebeurt er als je een uitzondering gooit uit een noexcept-functie?

Er wordt std::terminate aangeroepen, het programma wordt abrupt afgesloten. noexcept is een strikte overeenkomst.

Kun je uitzonderingen op value vangen? Waarom is dit gevaarlijk?

Je kunt op value vangen, maar het object wordt gekopieerd (object slicing). Het wordt aanbevolen om const & te gebruiken.

Voorbeeldcode:

try { throw std::out_of_range("err"); } catch (const std::exception& e) { /* ... */ }

Typische fouten en anti-patronen

  • Gebruik van throw in destructors
  • Het verzwijgen van uitzonderingen catch(...) zonder logging
  • Geen noexcept vermelding waar mogelijk

Voorbeeld uit het leven

Negatieve casus

De code gooide uitzonderingen in destructors van bronnen; bij een abrupte afsluiting werd de stack niet correct uitgepakt, bronnen bleven lekken.

Voordelen:

  • Snelle detectie van fouten mogelijk

Nadelen:

  • Programma's eindigden vaak met een terminate-fout

Positieve casus

Kritieke methoden waren gemarkeerd met noexcept, destructors verwerkten alle uitzonderingen in hun eigen code. Catch werd met referentie toegepast, alle fouten werden gelogd.

Voordelen:

  • Betrouwbaarheid, geen lekken
  • Uiterst voorspelbaar gedrag

Nadelen:

  • Verhoogde striktheid voor de ontwikkelaar bij het schrijven van correcte, "schone" code