Condividi tramite


Gestione strutturata delle eccezioni (C/C++)

Sebbene Windows e Visual C++ supportino la gestione strutturata delle eccezioni (SEH), è consigliabile utilizzare la gestione delle eccezioni di ISO-standard C++ in quanto rende il codice più portabile e flessibile. Tuttavia, in codice esistente o per particolari tipi di programmi, potrebbe essere necessario utilizzare SEH.

Grammatica

try-except-statement :

__try compound-statement

__except ( expression ) compound-statement

Note

Utilizzando SEH, è possibile assicurarsi che le risorse quali i blocchi di memoria e file siano corretti se l'esecuzione termina in modo inatteso. È inoltre possibile gestire problemi specifici —ad esempio memoria insufficiente— usando del codice strutturato conciso che non si basa sulle istruzioni goto o su test elaborati dei codici di ritorno.

Le istruzioni try-except e try-finally considerate in questo articolo sono estensioni Microsoft il linguaggio C. Supportano SEH consentendo alle applicazioni di ottenere il controllo di un programma dopo eventi che terminerebbero altrimenti l'esecuzione. Sebbene SEH lavori con i file sorgenti C++, non è progettata specificamente per C++. Se si utilizza SEH in un programma C++ che viene compilato con l'opzione /EH —insieme con determinati modificatori—, vengono richiamati i distruttori per gli oggetti locali, ma altro comportamento di esecuzione potrebbe non essere quello previsto. (Per informazioni generali, vedere l'esempio più avanti in questo articolo.) Nella maggior parte dei casi, anziché SEH si consiglia di utilizzare lo standard ISO Gestione delle eccezioni C++, supportato inoltre da Visual C++. Tramite la gestione delle eccezioni C++, è possibile garantire maggiore portabilità del codice ed è possibile gestire le eccezioni di qualsiasi tipo.

Se si dispone di moduli C che utilizzano SEH, è possibile mischiarli con moduli C++ che utilizzano la gestione delle eccezioni C++. Per ulteriori informazioni, vedere Differenze nella gestione eccezioni.

Esistono due meccanismi SEH:

Questi due tipi di gestori sono diversi, ma sono strettamente correlati a un processo noto come "rimozione dello stack." Quando si verifica un'eccezione, Windows cerca il gestore delle eccezioni di più recente installazione che è attualmente attivo. Il gestore può effettuare una delle tre operazioni:

  • Non riuscire a riconoscere l'eccezione e passare il controllo ad altri gestori.

  • Riconoscere l'eccezione ma ignorarla.

  • Riconoscere l'eccezione e gestirla.

Il gestore di eccezioni che riconosce l'eccezione può non essere incluso nella funzione che era in esecuzione quando si è verificata l'eccezione. In alcuni casi, può trovarsi in una funzione collocata in una posizione molto più alta nello stack. La funzione attualmente in esecuzione e tutte le altre funzioni dello stack frame vengono terminate. Durante questo processo, lo stack viene "rilassato", ovvero, le variabili locali di funzioni terminate —a meno che esse siano static—verranno cancellate dallo stack.

Come rilassa lo stack, il sistema operativo richiama tutti i gestori di terminazione scritti per ciascuna funzione. Utilizzando un gestore di terminazione, è possibile pulire le risorse che rimarrebbero altrimenti aperte a causa di una terminazione anomala. Se è stata fatto accesso ad una sezione critica, è possibile uscirne nel gestore di terminazione. Se il programma verrà interrotto, è possibile eseguire altre attività, quali la chiusura e la rimozione dei file temporanei.

Per ulteriori informazioni, vedere:

Esempio

Come detto in precedenza, i distruttori per gli oggetti locali vengono chiamati se viene utilizzato SEH in un programma C++ e si compila utilizzando l'opzione /EH con determinati modificatori— ad esempio, /EHsc e /EHa. Tuttavia, il comportamento durante l'esecuzione potrebbe non essere quello previsto se si utilizzano le eccezioni C++. Nell'esempio seguente vengono illustrate queste differenze di comportamento.

#include <stdio.h>
#include <Windows.h>
#include <exception>
 
class TestClass
{
public:
    ~TestClass()
    {
        printf("Destroying TestClass!\r\n");
    }
};
 
__declspec(noinline) void TestCPPEX()
{
#ifdef CPPEX
    printf("Throwing C++ exception\r\n");
    throw std::exception("");
#else
    printf("Triggering SEH exception\r\n");
    volatile int *pInt = 0x00000000;
    *pInt = 20;
#endif
}
 
__declspec(noinline) void TestExceptions()
{
    TestClass d;
    TestCPPEX();
}
 
int main()
{
    __try
    {
        TestExceptions();
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
        printf("Executing SEH __except block\r\n");
    }
 
    return 0;
}

Se si utilizza /EHsc per compilare il codice, ma il controllo CPPEX dei test locale è indefinito, non esiste alcuna esecuzione del distruttore di TestClass e l'output è analogo al seguente:

  

Se si utilizza /EHsc per compilare il codice e CPPEX viene definito tramite /DCPPEX (in modo da generare l'eccezione C++), il distruttore TestClass viene eseguito e l'output è analogo al seguente:

  

Se si utilizza /EHa per compilare il codice, il distruttore TestClass viene eseguito indipendentemente dal fatto che l'eccezione sia stata generata utilizzando std::throw oppure utilizzando SEH per attivare l'eccezione (con CPPEX definito oppure no). L'output è il seguente:

  

Per ulteriori informazioni, vedere /EH (Modello di gestione delle eccezioni).

Vedere anche

Riferimenti

Gestione di eccezioni in Visual C++

Parole chiave C++

<exception>

Concetti

Gestione di errori ed eccezioni (C++ moderno)

Altre risorse

Gestione strutturata delle Eccezioni (Windows)