Waarom wordt er geen beroep gedaan op destructor?

Ik had verwacht dat A::~A()in dit programma zou worden aangeroepen, maar dat is niet zo:

#include <iostream>
struct A {
  ~A() { std::cout << "~A()" << std::endl; }
};
void f() {
  A a;
  throw "spam";
}
int main() { f(); }

Als ik echter de laatste regel verander in

int main() try { f(); } catch (...) { throw; }

vervolgens A::~A()wordtgenoemd.

Ik compileer met “Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.762 for 80×86” van Visual Studio 2005. De opdrachtregel is cl /EHa my.cpp.

Heeft de compiler zoals gewoonlijk gelijk? Wat zegt standaard hierover?


Antwoord 1, autoriteit 100%

De destructor wordt niet aangeroepen omdat beëindiging() voor de onverwerkte uitzondering wordt aangeroepen voordat de stapel wordt afgewikkeld.

De specifieke details van wat de C++-specificatie zegt, valt buiten mijn kennis, maar een debug-tracering met gdb en g++ lijkt dit te bevestigen.

Volgens de conceptstandaardsectie 15.3 opsommingsteken 9:

9 Als er geen overeenkomende handler in een programma wordt gevonden, wordt de functie beëindig()
 (_behalve.terminate_) wordt aangeroepen. Of de stapel al dan niet is afgewikkeld
 voordat u termineren() aanroept, is door de implementatie gedefinieerd.

Antwoord 2, autoriteit 24%

C++ taalspecificatie stelt:
Het proces van het aanroepen van destructors voor automatische objecten die zijn geconstrueerd op het pad van een try-blok naar een throw-expressie wordt “stack afwikkeling” genoemd.
Uw originele code bevat geen try-blok, daarom vindt het afwikkelen van de stapel niet plaats.


Antwoord 3, autoriteit 4%

Sorry dat ik geen kopie van de standaard bij me heb.
Ik zou hier zeker een definitief antwoord op willen hebben, dus iemand met een kopie van de standaard wil hoofdstuk en vers delen over wat er gebeurt:

Voor zover ik weet wordt beëindigen alleen iff genoemd:

  • Het mechanisme voor het afhandelen van uitzonderingen kan geen handler vinden voor een gegenereerde uitzondering.
    De volgende zijn meer specifieke gevallen hiervan:

    • Tijdens het afwikkelen van de stapel ontsnapt een uitzondering aan een destructor.
    • Een gegenereerde expressie, een uitzondering ontsnapt aan de constructor.
    • Een uitzondering ontsnapt aan de constructor/destructor van een niet-lokale statische (dwz globale)
    • Een uitzondering ontsnapt aan een functie die is geregistreerd met atexit().
    • Een uitzondering ontsnapt aan main()
  • Proberen een uitzondering opnieuw te maken terwijl er momenteel geen uitzondering wordt verspreid.
  • Een onverwachte uitzondering ontsnapt aan een functie met uitzonderingsspecificaties (via onverwacht)

Antwoord 4, autoriteit 3%

In het tweede voorbeeld wordt de dtor aangeroepen wanneer deze het try{}-blok verlaat.

In het eerste voorbeeld wordt de dtor aangeroepen als het programma wordt afgesloten na het verlaten van de functie main() — tegen die tijd kan het zijn dat cout al is vernietigd.


Antwoord 5, autoriteit 3%

Ik nam ook aan dat de compiler de code niet relatief aan “a” genereert omdat er niet naar wordt verwezen, maar toch, het is niet het juiste gedrag omdat de destructor iets doet dat moet worden uitgevoerd.

Dus ik probeerde in VS2008/vc9 (+SP1), Debug en Release en ~A wordt aangeroepen nadat de uitzondering is gegooid, om uit f() te komen – dat is het juiste gedrag, als ik gelijk heb.

Nu heb ik het net geprobeerd met VS2005/vc8 (+SP1) en het is hetzelfde gedrag.

Ik heb breekpunten gebruikt om zeker te zijn. Ik heb zojuist met de console gecontroleerd en ik heb ook het bericht “~A”. Misschien heb je het ergens anders verkeerd gedaan?


Antwoord 6, autoriteit 3%

Deze vraag is gemakkelijk te googlen, dus ik deel mijn situatie hier.

Zorg ervoor dat uw uitzondering de extern "C"-grens niet overschrijdt of gebruik MSVC-optie /EHs (C++-uitzonderingen inschakelen = Ja met externe C-functies (/EHs))

Other episodes