Udostępnij za pośrednictwem


Wyjątki i stosu niekontrolowanej w języku C++

W mechanizmie wyjątków C++ kontroli przenosi się z instrukcji throw pierwszej instrukcji catch, który może obsługiwać wyrzucony typu.Gdy osiągnięty zostanie instrukcja catch, wszystkie zmienne automatyczne, które są w zakresie między throw i zestawień połowowych są niszczone w procesie, który jest znany jako stosu, odwracanie.W stosie odwracanie, wpływy wykonanie następująco:

  1. Sterowanie osiągnie try oświadczenie normalne wykonanie sekwencyjnego.W sekcji strzeżonym w try bloku jest wykonywany.

  2. Jeśli nie jest wyjątek podczas wykonywania sekcji strzeżony catch klauzule, które należy wykonać try bloku nie są wykonywane.Kontynuuje wykonywanie w instrukcji po ostatnim catch klauzuli, która następuje związanych z nimi try bloku.

  3. Jeśli jest wyjątek podczas wykonywania strzeżony sekcji lub wszelkie rutynowych sekcji strzeżony wywołuje bezpośrednio lub pośrednio, obiekt wyjątku jest tworzony z obiektu, który jest tworzony przez throw operand.(Oznacza to może być zaangażowany Konstruktor kopiujący.) W tym momencie kompilator wygląda catch klauzula w wyższej kontekst wykonywania, który może obsłużyć wyjątek typu, który jest generowany, lub dla catch obsługi, które można rozpoznać dowolny typ wyjątku.catch Programy obsługi są badane w kolejności ich występowania w po try bloku.Jeśli stwierdzono nie obsługi odpowiedniego, następnie dynamicznie otaczający try bloku jest badany.Ten proces jest kontynuowany aż do najbardziej oddalonych otaczający try bloku jest badany.

  4. Jeśli pasujące obsługi nadal nie można odnaleźć lub jeśli wystąpi wyjątek podczas rozwijania procesów lecz przed obsługi pobiera formant, wstępnie zdefiniowanych funkcji terminate nazywa się.Jeśli wystąpi wyjątek po wyjątku, ale przed rozpoczęciem odkręcanie, terminate nazywa się.

  5. Jeśli pasująca catch znajduje się program obsługi i w drodze wartości, jego parametrów formalnych jest inicjowany przez kopiowanie obiektu wyjątek.Jeżeli połowy przez odniesienie, parametr jest inicjowany do odwoływania się do obiektu wyjątek.Po zainicjowaniu parametrów formalnych, rozpoczyna się proces odwracanie stosu.Wiąże się to zniszczenie wszystkich obiektów automatycznego, które zostały skonstruowane całkowicie — ale jeszcze nie zniszczony — między początkiem try bloku, który jest skojarzony z catch obsługi i witryny rzut wyjątku.Zniszczenia w odwrotnej kolejności występuje budowy.catch Program obsługi jest wykonywany i program wznawia wykonanie po ostatnim obsługi — oznacza to, że w pierwszej instrukcji lub konstrukcję, która nie jest catch obsługi.Formant można wprowadzać tylko catch obsługi poprzez wyrzucony wyjątek, nigdy nie poprzez goto instrukcja lub case etykiety na switch instrukcji.

Przykład odwijania stosu

Poniższy przykład ilustruje, jak stos jest zlikwidowany, gdy występuje wyjątek.Wykonanie na wątku przechodzi od instrukcji throw w C instrukcji catch w maini odkręcania każdej funkcji po drodze.Należy zauważyć, w jakiej kolejności Dummy obiekty są tworzone, a następnie niszczone, ponieważ wykraczają one poza zakres.Zauważ, że funkcja nie kończy się z wyjątkiem main, który zawiera instrukcja catch.Funkcja A nigdy nie wróci z wywołania do B(), i B nigdy nie wróci z wywołania do C().Jeżeli definicja Dummy wskaźnik i odpowiadających im delete instrukcja i następnie uruchomić program, należy zauważyć, że wskaźnik nigdy nie jest usuwane.Pokazuje to, co może się zdarzyć, gdy funkcje nie zapewniają gwarancji wyjątek.Aby uzyskać więcej informacji, zobacz temat jak: Projektowanie dla wyjątków.Jeśli komentarz się instrukcja catch, można zaobserwować, co się dzieje, gdy program kończy działanie z powodu nieobsłużonego wyjątku.

#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.
 
*/