Eccezioni e rimozione dallo stack in C++
Nel meccanismo di eccezioni di C++, il controllo si sposta dall'istruzione throw alla prima istruzione catch che può gestire il tipo generato. Quando viene raggiunta l'istruzione catch, tutte le variabili automatiche incluse nell'ambito tra le istruzioni throw e catch vengono eliminate definitivamente in un processo noto come rimozione dello stack. Nella rimozione dello stack, l'esecuzione procede come segue:
Il controllo raggiunge l'istruzione in base alla
try
normale esecuzione sequenziale. Viene eseguita la sezione sorvegliata neltry
blocco.Se non viene generata alcuna eccezione durante l'esecuzione della sezione sorvegliata, le
catch
clausole che seguono iltry
blocco non vengono eseguite. L'esecuzione continua con l'istruzione dopo l'ultimacatch
clausola che segue il blocco associatotry
.Se viene generata un'eccezione durante l'esecuzione della sezione sorvegliata o in qualsiasi routine che la sezione sorvegliata chiama direttamente o indirettamente, viene creato un oggetto eccezione dall'oggetto creato dall'operando
throw
. Ciò implica che potrebbe essere coinvolto un costruttore di copia. A questo punto, il compilatore cerca unacatch
clausola in un contesto di esecuzione superiore in grado di gestire un'eccezione del tipo generato o per uncatch
gestore in grado di gestire qualsiasi tipo di eccezione. Icatch
gestori vengono esaminati in ordine di aspetto dopo iltry
blocco. Se non viene trovato alcun gestore appropriato, viene esaminato il successivo blocco di inclusionetry
dinamica. Questo processo continua fino a quando non viene esaminato il blocco di inclusionetry
più esterno.Se anche in questo modo non viene individuato alcun gestore appropriato o se si verifica un'eccezione durante il processo di rimozione, ma prima che il gestore ottenga il controllo, la funzione di runtime predefinita
terminate
viene chiamata. Se si verifica un'eccezione dopo la generazione dell'eccezione ma prima che la rimozione abbia inizio, viene chiamatoterminate
.Se viene trovato un gestore corrispondente
catch
e intercetta per valore, il relativo parametro formale viene inizializzato copiando l'oggetto eccezione. Se le rilevazioni sono effettuate per riferimento, il parametro viene inizializzato in modo da fare riferimento all'oggetto eccezione. In seguito all'inizializzazione del parametro formale, ha inizio il processo di rimozione dello stack. Ciò comporta la distruzione di tutti gli oggetti automatici completamente costruiti, ma non ancora distrutto, tra l'inizio deltry
blocco associato alcatch
gestore e il sito di generazione dell'eccezione. La distruzione ha luogo in ordine inverso rispetto alla costruzione. Ilcatch
gestore viene eseguito e il programma riprende l'esecuzione dopo l'ultimo gestore, ovvero alla prima istruzione o costrutto che non è uncatch
gestore. Il controllo può immettere uncatch
gestore solo tramite un'eccezione generata, mai tramite un'istruzionegoto
o un'etichettacase
in un'istruzioneswitch
.
Esempio di rimozione dello stack
L'esempio seguente illustra le modalità di rimozione dello stack quando viene generata un'eccezione. L'esecuzione nel thread passa dall'istruzione throw in C
all'istruzione catch in main
e rimuove tutte le funzioni che incontra sul suo percorso. Si noti l'ordine in cui gli oggetti Dummy
vengono creati e poi distrutti quando diventano esterni all'ambito. Si noti, inoltre, che nessuna funzione è completa, ad eccezione di main
, che contiene l'istruzione catch. La funzione A
non viene mai restituita dalla relativa chiamata a B()
e B
non viene mai restituita dalla relativa chiamata a C()
. Si noti che, se dalla definizione del puntatore Dummy
si rimuovono il commento e l'istruzione di eliminazione corrispondente e, successivamente, si esegue il programma, il puntatore non viene mai eliminato. Questo indica ciò che può verificarsi quando le funzioni non forniscono una garanzia di eccezione. Per altre informazioni, vedere Procedura: Progettare per le eccezioni. Se si inserisce un commento al di fuori dell'istruzione catch, è possibile osservare ciò 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.
*/
Commenti e suggerimenti
https://aka.ms/ContentUserFeedback.
Presto disponibile: Nel corso del 2024 verranno gradualmente disattivati i problemi di GitHub come meccanismo di feedback per il contenuto e ciò verrà sostituito con un nuovo sistema di feedback. Per altre informazioni, vedereInvia e visualizza il feedback per