Udostępnij za pośrednictwem


Obsługa wyjątków strukturalnych (C/C++)

Chociaż system Windows i Visual C++ wspierają strukturalną obsługę wyjątków (SEH), zaleca się użyć obsługi wyjątków normy ISO C++, ponieważ dzięki niej kod jest bardziej przenośny i elastyczny.Niemniej jednak w istniejącym kodzie lub dla szczególnych rodzajów programów, nadal można używać SEH.

Gramatyka

try-except-statement :

__try compound-statement

__except ( expression ) compound-statement

Uwagi

Ze strukturalną obsługą wyjątków, można zagwarantować, że zasoby, takie jak bloki pamięci i pliki będą poprawne, jeśli wykonanie zostanie niespodziewanie przerwane.Można również obsługiwać specyficzne problemy, na przykład niewystarczającej ilości pamięci - przez użycie zwięzłego kodu strukturalnego, który nie opiera się na instrukcjach goto lub opracowanie testowania zwracanych kodów.

Instrukcje try-except i try-finally, o których mowa w artykule, są rozszerzeniami Microsoft do języka C.Wspierają one strukturalną obsługę wyjątków, umożliwiając aplikacjom przejęcie kontroli nad programem po zdarzeniach, które w przeciwnym razie przerwałyby wykonywanie.Chociaż strukturalna obsługa wyjątków działa z plikami źródłowymi języka C++, to nie została opracowana specjalnie dla języka C++.Jeśli używasz strukturalnej obsługi wyjątków w programie C++, który można skompilować przy użyciu opcji /EH - wraz z pewnymi modyfikatorami - wywoływane są destruktory obiektów lokalnych, ale pozostały sposób wykonywania może być inny niż oczekiwany. (Dla zobrazowania, zobacz przykład w dalszej części artykułu.) W większości przypadków, zamiast strukturalnej obsługi wyjątków firma Microsoft zaleca użycie normy ISO obsługa wyjątków C++, która wspiera też język Visual C++.Stosując obsługę wyjątków C++, można zapewnić większą przenośność kodu, a także obsługę wyjątków dowolnego typu.

Jeśli użytkownik ma moduły C, które używają strukturalnej obsługi wyjątków, może je łączyć z modułami C++, które używają obsługi wyjątków C++.Aby uzyskać więcej informacji, zobacz Różnice w obsłudze wyjątków.

Istnieją dwa mechanizmy strukturalnej obsługi wyjątków:

Powyższe dwa rodzaje programów obsługi różnią się od siebie, ale są ściśle powiązane przez proces znany jako "rozwijanie stosu". Gdy wystąpi wyjątek, system Windows wyszuka ostatnio zainstalowany program obsługi wyjątków, który jest aktualnie aktywny.Program obsługi może zachować się na trzy sposoby:

  • Nie udało się rozpoznać wyjątku i przekazać sterowania do innych programów obsługi.

  • Rozpoznać wyjątek, ale go zignorować.

  • Rozpoznać wyjątek i obsłużyć go.

Program obsługi wyjątków, który rozpoznaje wyjątek może nie znajdować się w funkcji, która była uruchomiona podczas wystąpienia wyjątku.W niektórych przypadkach może znajdować się w funkcji będącej znacznie wyższej na stosie.Aktualnie uruchomiona funkcja i wszystkie inne funkcje na ramce stosu zostają zakończone.Podczas tego procesu, stos jest "rozwijany", tzn. zmienne lokalne zakończonych funkcji - o ile nie mają modyfikatora dostępu static - są usuwane ze stosu.

Podczas rozwijania stosu, system operacyjny nie wywołuje żadnych programów obsługi zakończeń, które zostały napisane dla każdej funkcji.Za pomocą programu obsługi zakończeń, można oczyścić zasoby, które inaczej pozostałyby otwarte ze względu na nieprawidłowe zakończenie.Jeśli została wprowadzona sekcja krytyczna, można zakończyć ten tryb w programie obsługi rozwiązań.Jeśli program będzie wkrótce zamknięty, użytkownik może wykonać inne zadania porządkowe, takie jak zamykanie oraz usuwanie plików tymczasowych.

Aby uzyskać więcej informacji, zobacz:

Przykład

Jak wspomniano wcześniej, destruktory dla obiektów lokalnych są wywoływane, jeżeli użytkownik używa strukturalnej obsługi wyjątków w programie w języku C++ i skompiluje go za pomocą opcji /EH z określonymi modyfikatorami, na przykład /EHsc i /EHa.Jednakże jeśli używane są także wyjątki C++, zachowanie podczas wykonywania może nie być zgodne z oczekiwaniami.Poniższy przykład demonstruje wspomniane różnice funkcjonalne.

#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;
}

Jeśli użytkownik wykorzystuje /EHsc, aby skompilować powyższy kod, ale kontrolka testu lokalnego CPPEX jest niezdefiniowana, destruktor TestClass niczego nie wykonuje i wyjście wygląda następująco:

  

Jeśli użytkownik wykorzystuje /EHsc, aby skompilować kod i kontrolka CPPEX jest zdefiniowana za pomocą /DCPPEX (tak, aby zgłoszony został wyjątek C++), wykonywane są czynności destruktora TestClass i wyjście wygląda następująco:

  

Jeśli użytkownik wykorzystuje /EHa, aby skompilować kod, czynności destruktora TestClass są wykonywane niezależnie od tego, czy wyjątek został zgłoszony przy użyciu std::throw, czy za pomocą strukturalnej obsługi wyjątków (kontrolka CPPEX może być zdefiniowana lub nie).Wyjście wygląda następująco:

  

Aby uzyskać więcej informacji, zobacz /EH (Model obsługi wyjątku).

Zobacz też

Informacje

Obsługa wyjątków w języku Visual C++

Słowa kluczowe języka C++

<exception>

Koncepcje

Błędy w obsłudze wyjątków (Modern C++)

Inne zasoby

Strukturalna obsługa wyjątków (Windows)