Condividi tramite


Eccezioni e rimozione dello stack in C++

Il meccanismo di eccezioni C++, verificare i movimenti dall'istruzione throw alla prima istruzione catch che può gestire il tipo generato.Quando l'istruzione catch viene raggiunta, tutte le variabili automatiche inclusi nell'ambito tra la generazione e le istruzioni catch vengono eliminati in un processo noto come rimozione dello stack.La rimozione dello stack, l'esecuzione continua come segue:

  1. Il controllo raggiunge l'istruzione try tramite l'esecuzione sequenziale normale.La sezione accessibile nel blocco try eseguita.

  2. Se non viene generata alcuna eccezione durante l'esecuzione della sezione accessibile, le clausole catch che seguono il blocco try non vengono eseguite.L'esecuzione continua a un'istruzione dopo l'ultima istruzione catch che segue il blocco collegato try.

  3. Se viene generata un'eccezione durante l'esecuzione della sezione accessibile o in qualsiasi routine che la sezione accessibile chiama direttamente o indirettamente, un oggetto eccezione viene creato dall'oggetto creato dall'operando throw.(Questo implica che un costruttore di copia può essere coinvolto.) In questa fase, il compilatore rileva una clausola catch in un contesto di esecuzione più elevato che può gestire un'eccezione di tipo generato, o per un gestore catch in grado di gestire qualsiasi tipo di eccezione.I gestori catch vengono valutati per il loro aspetto dopo che il blocco try.Se nessun gestore appropriato viene trovato, il blocco di inclusione in modo dinamico riportato try viene esaminato.Questo processo continua fino a individuare il blocco di inclusione più esterno try.

  4. Se un gestore corrispondente non viene trovato, o se si verifica un'eccezione durante il processo di rimozione ma prima del gestore ottenere il controllo, la funzione di runtime predefinita terminate è denominata.Se si verifica un'eccezione dopo l'eccezione viene generata ma prima che il rimuovere iniziare, terminate viene chiamato.

  5. Se un gestore catch corrispondente viene trovato e intercetta per valore, il relativo parametro formale viene inizializzato copia dell'oggetto eccezione.Se rileva per riferimento, il parametro viene inizializzato per fare riferimento all'oggetto eccezione.Dopo il parametro formale inizializzata, il processo di rimozione dello stack inizia.Ciò include la distruzione di tutti gli oggetti automatici contenuti completamente costruire- ma non ancora destructed- tra l'inizio del blocco try associato al gestore catch e il sito di generazione di un'eccezione.La distruzione si verifica in ordine inverso di costruzione.Il gestore catch viene eseguito e l'esecuzione di riprende di programma dopo l'ultimo gestore, ovvero alla prima istruzione o costrutto non è un gestore catch.Il controllo può registrare solo un gestore catch con un'eccezione, mai tramite un'istruzione goto o un'etichetta case in un'istruzione switch.

Esempio di rimozione dello stack

Nell'esempio seguente viene illustrato come lo stack viene rimosso quando viene generata un'eccezione.L'esecuzione del thread passa dall'istruzione throw in C all'istruzione catch in maine rimuove ogni funzione lungo la strada.Si noti l'ordine in cui gli oggetti Dummy vengono creati e quindi vengono eliminati quando escono dall'ambito.Si noti inoltre che nessuna funzione completa tranne main, che contiene l'istruzione catch.Di funzione A restituisce mai dalla chiamata a B()e B restituisce mai dalla chiamata a C().Se si rimuove il commento dalla definizione del puntatore Dummy e l'istruzione corrispondente di eliminazione e si esegue il programma, si noti che il puntatore non viene eliminato mai.Indica che può verificarsi quando le funzioni non forniscono una garanzia di eccezione.Per ulteriori informazioni, vedere procedura: Progettazione delle eccezioni.Se impostate come commento l'istruzione catch, è possibile osservare che si verifica quando un programma termina a causa di un'eccezione non gestita.

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