Sdílet prostřednictvím


Výjimky a zásobníku příkazem jazyka C++

V mechanismu výjimek C++ ovládací prvek přesune z příkazu throw první příkaz catch, který lze zpracovat vyvolané typu.Jakmile je dosaženo příkazu catch, všechny automatické proměnné, které jsou v rozsahu mezi throw a příkazy catch jsou zničeny v procesu, který je známý jako zásobník unwind.V zásobníku unwind, spuštění výtěžek takto:

  1. Ovládací prvek dosáhne try prohlášení normální sekvenční provádění.V chráněné části try blok je proveden.

  2. Pokud výjimka během provádění chráněné části catch doložky, které následují try bloku nebudou provedeny.Pokračuje po poslední příkaz catch klauzule, který následuje přidruženého try bloku.

  3. Pokud během provádění chráněné části nebo v jakékoli části chráněné volá přímo nebo nepřímo rutina je vyvolána výjimka, je vytvořen objekt výjimky z objektu, který je vytvořen throw operand.(To znamená, že mohou být zapojeny kopie konstruktoru.) V tomto okamžiku kompilátor hledá catch klauzule vyšší kontext spuštění, které lze zpracovat výjimky, je vyvolána výjimka typu nebo pro catch rutinu, která dokáže zpracovat jakýkoliv typ výjimky.catch Obslužné rutiny jsou zkoumány v pořadí jejich vzhledu po try bloku.Pokud je nalezen žádný odpovídající obslužnou rutinu další dynamicky orámování try blok je zkontrolován.Tento proces pokračuje, dokud vnější orámování try blok je zkontrolován.

  4. Pokud stále nebyl nalezen odpovídající popisovač nebo pokud dojde k výjimce během procesu unwinding ale předtím, než získá obslužné rutiny prvku předdefinovanou funkci run-time terminate je volána.Po vyvolání výjimky, dojde k výjimce, ale před unwind, terminate je volána.

  5. Pokud odpovídající catch nalezena obslužná rutina a jeho úlovky hodnotu, jeho formální parametr je inicializován zkopírováním objekt výjimky.Pokud jej zachytí odkazem, parametr je inicializován odkazovat na objekt výjimky.Po inicializaci formálních parametrů zahájí proces unwind zásobníku.To zahrnuje zničení všech automatických objektů plně sestavené – ale ještě destructed – mezi začátkem try blok, který je spojen s catch webu throw výjimky a obslužné rutiny.Zničení dochází v obráceném pořadí stavby.catch Spuštění rutiny a program pokračuje v provádění po poslední rutiny –, na první příkaz nebo konstrukce, která není catch obslužné rutiny.Ovládacího prvku lze zadat pouze catch obslužnou rutinu prostřednictvím výjimky, nikdy prostřednictvím goto prohlášení nebo case popisku v switch prohlášení.

Příklad Unwinding zásobníku

Následující příklad ukazuje, jak je zásobník pokračuj, když je vyvolána výjimka.Přejde na podproces provádění příkazu throw v C k příkazu catch v maina unwinds funkce podél způsobem.Všimněte si pořadí, v němž Dummy objekty jsou vytvořeny a zlikvidovány jako jejich přejít mimo rozsah.Všimněte si také, že žádné funkce dokončí s výjimkou main, který obsahuje příkaz catch.Funkce A nikdy vrátí z jeho volání B(), a B nikdy vrátí z jeho volání C().Pokud jste definice Dummy ukazatel a odpovídající prohlášení, odstranit a potom spusťte program, Všimněte si, že ukazatel nikdy odstraněna.Ukazuje, co může nastat, když funkce neposkytují záruky výjimce.Další informace naleznete v tématu Jak: návrh pro výjimky.Jestliže poznámky příkaz catch můžete sledovat, co se stane při ukončení programu z důvodu neošetřené výjimky.

#include <string>
#include <iostream>
using namespace std;
 
class MyException{};
class Dummy
{
    public:
    Dummy(string s) : MyName(s) { PrintMsg("Created Dummy:"); }
    Dummy(const Dummy& other) : MyName(other.MyName){ PrintMsg("Copy created Dummy:"); }
    ~Dummy(){ PrintMsg("Destroyed Dummy:"); }
    void PrintMsg(string s) { cout << s  << MyName <<  endl; }
    string MyName; 
    int level;
};
 
 
void C(Dummy d, int i)
{ 
    cout << "Entering FunctionC" << endl;
    d.MyName = " C";
    throw MyException();   
 
    cout << "Exiting FunctionC" << endl;
}
 
void B(Dummy d, int i)
{
    cout << "Entering FunctionB" << endl;
    d.MyName = "B";
    C(d, i + 1);   
    cout << "Exiting FunctionB" << endl; 
}
 
void A(Dummy d, int i)
{ 
    cout << "Entering FunctionA" << endl;
    d.MyName = " A" ;
  //  Dummy* pd = new Dummy("new Dummy"); //Not exception safe!!!
    B(d, i + 1);
 //   delete pd; 
    cout << "Exiting FunctionA" << endl;   
}
 
 
int main()
{
    cout << "Entering main" << endl;
    try
    {
        Dummy d(" M");
        A(d,1);
    }
    catch (MyException& e)
    {
        cout << "Caught an exception of type: " << typeid(e).name() << endl;
    }
 
    cout << "Exiting main." << endl;
    char c;
    cin >> c;
}
 
/* Output:
    Entering main
    Created Dummy: M
    Copy created Dummy: M
    Entering FunctionA
    Copy created Dummy: A
    Entering FunctionB
    Copy created Dummy: B
    Entering FunctionC
    Destroyed Dummy: C
    Destroyed Dummy: B
    Destroyed Dummy: A
    Destroyed Dummy: M
    Caught an exception of type: class MyException
    Exiting main.
 
*/