W C++ wyjątki to anomalie w czasie wykonywania lub nietypowe warunki, które program napotyka podczas wykonywania. Proces obsługi tych wyjątków nazywany jest obsługą wyjątków. Korzystając z mechanizmu obsługi wyjątków, sterowanie z jednej części programu, w której wystąpił wyjątek, można przenieść do innej części kodu.
Zasadniczo używając obsługi wyjątków w C++, możemy obsłużyć wyjątki, aby nasz program nadal działał.
wydruk javascript
Co to jest wyjątek C++?
Wyjątkiem jest nieoczekiwany problem, który pojawia się podczas wykonywania programu. Nasz program nagle kończy się z pewnymi błędami/problemami. Wyjątek występuje podczas działania programu (runtime).
Typy wyjątków C++
W C++ istnieją dwa typy wyjątków
- Synchroniczny: Wyjątki zdarzają się, gdy coś pójdzie nie tak z powodu błędu w danych wejściowych lub gdy program nie jest przystosowany do obsługi bieżącego typu danych, z którymi pracuje, na przykład dzielenia liczby przez zero.
- Asynchroniczny : Wyjątki, na które program nie ma wpływu, takie jak awaria dysku, przerwania klawiatury itp.
C++ spróbuj złapać
C++ zapewnia wbudowaną funkcję obsługi wyjątków. Można to zrobić za pomocą następujących specjalistycznych słów kluczowych: spróbuj, złap i rzuć, przy czym każde z nich ma inny cel.
Składnia try-catch w C++
try { // Code that might throw an exception throw SomeExceptionType('Error message'); } catch ( ExceptionName e1 ) { // catch block catches the exception that is thrown from try block }> 1. spróbuj w C++
Słowo kluczowe try reprezentuje blok kodu, który może zgłosić wyjątek umieszczony wewnątrz bloku try. Po nim następuje jeden lub więcej bloków catch. Jeśli wystąpi wyjątek, try block zgłasza ten wyjątek.
2. złapać w C++
Instrukcja catch reprezentuje blok kodu, który jest wykonywany, gdy zostanie zgłoszony określony wyjątek z bloku try. Kod obsługujący wyjątek jest zapisany w bloku catch.
3. wrzuć C++
Wyjątek w C++ można zgłosić za pomocą słowa kluczowego rzut. Gdy program napotka instrukcję rzutu, natychmiast kończy bieżącą funkcję i zaczyna znajdować pasujący blok catch do obsługi zgłoszonego wyjątku.
Notatka: Można użyć wielu instrukcji catch do przechwytywania różnego typu wyjątków zgłaszanych przez blok try.
Słowa kluczowe try i catch występują w parach: używamy bloku try do testowania kodu, a jeśli kod zgłosi wyjątek, obsłużymy go w naszym bloku catch.
Dlaczego potrzebujemy Obsługa wyjątków w C++?
Poniżej przedstawiono główne zalety obsługi wyjątków w porównaniu z tradycyjną obsługą błędów:
- Oddzielenie kodu obsługi błędów od kodu normalnego : Zawsze istnieją warunki if-else umożliwiające obsługę błędów w tradycyjnych kodach obsługi błędów. Te warunki i kod obsługujący błędy są mylone z normalnym przepływem. To sprawia, że kod jest mniej czytelny i łatwy w utrzymaniu. Dzięki blokom try/catch kod obsługi błędów staje się oddzielony od normalnego przepływu.
- Funkcje/Metody mogą obsługiwać tylko wybrane przez siebie wyjątki : Funkcja może zgłosić wiele wyjątków, ale może zdecydować się na obsługę niektórych z nich. Inne wyjątki, które są zgłaszane, ale nie przechwycone, mogą być obsługiwane przez osobę wywołującą. Jeśli osoba wywołująca zdecyduje się ich nie łapać, wyjątki są obsługiwane przez osobę wywołującą osobę wywołującą.
W C++ funkcja może określić zgłaszane wyjątki za pomocą słowa kluczowego rzut. Osoba wywołująca tę funkcję musi w jakiś sposób obsłużyć wyjątek (albo poprzez ponowne określenie go, albo przechwycenie).
- Grupowanie typów błędów : W C++ jako wyjątki można zgłaszać zarówno typy podstawowe, jak i obiekty. Możemy stworzyć hierarchię obiektów wyjątków, grupować wyjątki w przestrzeniach nazw lub klasach i kategoryzować je według ich typów.
Przykłady obsługi wyjątków w C++
Poniższe przykłady pokazują, jak używać bloku try-catch do obsługi wyjątków w języku C++.
Przykład 1
Poniższy przykład ilustruje wyjątki zgłaszania w C++.
C++
// C++ program to demonstate the use of try,catch and throw> // in exception handling.> #include> #include> using> namespace> std;> int> main()> {> >// try block> >try> {> >int> numerator = 10;> >int> denominator = 0;> >int> res;> >// check if denominator is 0 then throw runtime> >// error.> >if> (denominator == 0) {> >throw> runtime_error(> >'Division by zero not allowed!'>);> >}> >// calculate result if no exception occurs> >res = numerator / denominator;> >//[printing result after division> >cout <<>'Result after division: '> << res << endl;> >}> >// catch block to catch the thrown exception> >catch> (>const> exception& e) {> >// print the exception> >cout <<>'Exception '> << e.what() << endl;> >}> >return> 0;> }> |
>
>Wyjście
Exception Division by zero not allowed!>
Przykład 2
Poniżej znajduje się prosty przykład pokazujący obsługę wyjątków w C++. Dane wyjściowe programu wyjaśniają przebieg wykonywania bloków try/catch.
CPP
// C++ program to demonstate the use of try,catch and throw> // in exception handling.> #include> using> namespace> std;> int> main()> {> >int> x = -1;> >// Some code> >cout <<>'Before try
'>;> >// try block> >try> {> >cout <<>'Inside try
'>;> >if> (x <0) {> >// throwing an exception> >throw> x;> >cout <<>'After throw (Never executed)
'>;> >}> >}> >// catch block> >catch> (>int> x) {> >cout <<>'Exception Caught
'>;> >}> >cout <<>'After catch (Will be executed)
'>;> >return> 0;> }> |
>
>Wyjście
Before try Inside try Exception Caught After catch (Will be executed)>
Właściwości obsługi wyjątków w C++
Właściwość 1
Istnieje specjalny blok catch zwany blokiem „catch-all”, zapisany jako catch(…), którego można używać do przechwytywania wszystkich typów wyjątków.
Przykład
W poniższym programie int jest zgłaszany jako wyjątek, ale nie ma bloku catch dla int, więc zostanie wykonany blok catch(…).
CPP
// C++ program to demonstate the use of catch all> // in exception handling.> #include> using> namespace> std;> int> main()> {> >// try block> >try> {> >// throw> >throw> 10;> >}> >// catch block> >catch> (>char>* excp) {> >cout <<>'Caught '> << excp;> >}> >// catch all> >catch> (...) {> >cout <<>'Default Exception
'>;> >}> >return> 0;> }> |
>
>Wyjście
Default Exception>
Własność 2
Niejawna konwersja typów nie jest wykonywana w przypadku typów pierwotnych.
Przykład
W poniższym programie „a” nie jest domyślnie konwertowane na int.
mój żywy krykiet.
CPP
//// C++ program to demonstate property 2: Implicit type> /// conversion doesn't happen for primitive types.> // in exception handling.> #include> using> namespace> std;> int> main()> {> >try> {> >throw> 'a'>;> >}> >catch> (>int> x) {> >cout <<>'Caught '> << x;> >}> >catch> (...) {> >cout <<>'Default Exception
'>;> >}> >return> 0;> }> |
eksploracja danych
>
>Wyjście
Default Exception>
Wyjście:
Default Exception>
Własność 3
Jeśli zostanie zgłoszony wyjątek, który nie zostanie nigdzie przechwycony, program kończy się nieprawidłowo.
Przykład
W poniższym programie rzucany jest znak, ale nie ma bloku catch, który mógłby go przechwycić.
CPP
// C++ program to demonstate property 3: If an exception is> // thrown and not caught anywhere, the program terminates> // abnormally in exception handling.> #include> using> namespace> std;> int> main()> {> >try> {> >throw> 'a'>;> >}> >catch> (>int> x) {> >cout <<>'Caught '>;> >}> >return> 0;> }> |
>
>
Wyjście
terminate called after throwing an instance of 'char'>
Możemy zmienić to nietypowe zachowanie związane z zakończeniem, pisząc naszą nieoczekiwaną funkcję.
Notatka : Wyjątek klasy pochodnej powinien zostać przechwycony przed wyjątkiem klasy bazowej.
Podobnie jak Java, biblioteka C++ ma standardowy wyjątek class, która jest klasą bazową dla wszystkich standardowych wyjątków. Wszystkie obiekty generowane przez komponenty biblioteki standardowej pochodzą z tej klasy. Dlatego wszystkie standardowe wyjątki można przechwycić, przechwytując ten typ.
Właściwość 4
W przeciwieństwie do Javy, w C++ wszystkie wyjątki nie są zaznaczane, co oznacza, że kompilator nie sprawdza, czy wyjątek został przechwycony, czy nie (zobacz Ten dla szczegółów). Zatem nie jest konieczne określanie wszystkich nieprzechwyconych wyjątków w deklaracji funkcji. Jednak obsługa wyjątków jest zalecaną praktyką.
Przykład
Poniższy program kompiluje się dobrze, ale w idealnym przypadku podpis fun() powinien zawierać listę niesprawdzonych wyjątków.
CPP
przekreślenie
// C++ program to demonstate property 4 in exception> // handling.> #include> using> namespace> std;> // This function signature is fine by the compiler, but not> // recommended. Ideally, the function should specify all> // uncaught exceptions and function signature should be> // 'void fun(int *ptr, int x) throw (int *, int)'> void> fun(>int>* ptr,>int> x)> {> >if> (ptr == NULL)> >throw> ptr;> >if> (x == 0)> >throw> x;> >/* Some functionality */> }> int> main()> {> >try> {> >fun(NULL, 0);> >}> >catch> (...) {> >cout <<>'Caught exception from fun()'>;> >}> >return> 0;> }> |
>
>Wyjście
Caught exception from fun()>
Lepszy sposób na napisanie powyższego kodu:
CPP
// C++ program to demonstate property 4 in better way> #include> using> namespace> std;> // Here we specify the exceptions that this function> // throws.> void> fun(>int>* ptr,>int> x)>throw>(> >int>*,>int>)>// Dynamic Exception specification> {> >if> (ptr == NULL)> >throw> ptr;> >if> (x == 0)> >throw> x;> >/* Some functionality */> }> int> main()> {> >try> {> >fun(NULL, 0);> >}> >catch> (...) {> >cout <<>'Caught exception from fun()'>;> >}> >return> 0;> }> |
>
>Wyjście
Caught exception from fun()>
Notatka : Użycie specyfikacji wyjątków dynamicznych jest przestarzałe od wersji C++ 11. Jedną z przyczyn może być to, że może losowo przerwać działanie programu. Może się to zdarzyć, gdy zgłosisz wyjątek innego typu, który nie jest wymieniony w specyfikacji wyjątku dynamicznego. Twój program zakończy działanie, ponieważ w tym scenariuszu wywołuje (pośrednio) metodętermination(), która domyślnie wywołuje funkcję abort().
Własność 5
W C++ bloki try/catch można zagnieżdżać. Ponadto wyjątek można zgłosić ponownie za pomocą rzutu; .
Przykład
Poniższy program pokazuje zagnieżdżanie bloków try/catch.
CPP
jeśli inaczej, jeśli inaczej, jeśli Java
// C++ program to demonstrate try/catch blocks can be nested> // in C++> #include> using> namespace> std;> int> main()> {> >// nesting of try/catch> >try> {> >try> {> >throw> 20;> >}> >catch> (>int> n) {> >cout <<>'Handle Partially '>;> >throw>;>// Re-throwing an exception> >}> >}> >catch> (>int> n) {> >cout <<>'Handle remaining '>;> >}> >return> 0;> }> |
>
>Wyjście
Handle Partially Handle remaining>
Funkcja może również ponownie rzucić funkcję, używając tego samego rzutu; składnia. Funkcja może obsłużyć część i poprosić osobę wywołującą o obsługę pozostałej części.
Własność 6
Kiedy zostanie zgłoszony wyjątek, wszystkie obiekty utworzone wewnątrz otaczającego go bloku try zostaną zniszczone, zanim kontrola zostanie przeniesiona do bloku catch.
Przykład
Poniższy program demonstruje powyższą właściwość.
CPP
// C++ program to demonstrate> #include> using> namespace> std;> // Define a class named Test> class> Test {> public>:> >// Constructor of Test> >Test() { cout <<>'Constructor of Test '> << endl; }> >// Destructor of Test> >~Test() { cout <<>'Destructor of Test '> << endl; }> };> int> main()> {> >try> {> >// Create an object of class Test> >Test t1;> >// Throw an integer exception with value 10> >throw> 10;> >}> >catch> (>int> i) {> >// Catch and handle the integer exception> >cout <<>'Caught '> << i << endl;> >}> }> |
>
>Wyjście
Constructor of Test Destructor of Test Caught 10>
Ograniczenia obsługi wyjątków w C++
Obsługa wyjątków w C++ również ma kilka ograniczeń:
- Wyjątki mogą przerwać strukturę lub przepływ kodu, ponieważ w kodzie utworzonych jest wiele niewidocznych punktów wyjścia, co utrudnia odczytanie i debugowanie kodu.
- Jeśli obsługa wyjątków nie zostanie wykonana prawidłowo, może również prowadzić do wycieków zasobów.
- Trudno jest nauczyć się pisać kod wyjątku, który jest bezpieczny.
- Nie ma standardu C++ dotyczącego obsługi wyjątków, dlatego istnieje wiele odmian praktyk obsługi wyjątków.
Wniosek
Obsługa wyjątków w C++ jest używana do obsługi nieoczekiwanych zdarzeń przy użyciu bloków try i catch w celu skutecznego zarządzania problemem. Ta obsługa wyjątków sprawia, że nasze programy są bardziej niezawodne, ponieważ błędy w czasie wykonywania mogą być obsługiwane oddzielnie, a także pomaga zapobiegać awariom programu i nagłemu kończeniu programu w przypadku napotkania błędu.
Powiązane artykuły:
- Najczęstsze pytania i odpowiedzi dotyczące obsługi wyjątków w języku C++
- Quiz na temat obsługi wyjątków w C++