I C++ er unntak kjøretidsavvik eller unormale forhold som et program møter under kjøringen. Prosessen med å håndtere disse unntakene kalles unntakshåndtering. Ved å bruke unntakshåndteringsmekanismen kan kontrollen fra en del av programmet der unntaket skjedde overføres til en annen del av koden.
Så ved å bruke unntakshåndtering i C++, kan vi håndtere unntakene slik at programmet fortsetter å kjøre.
noe rask sortering
Hva er et C++-unntak?
Et unntak er et uventet problem som oppstår under kjøringen av et program programmet vårt avsluttes plutselig med noen feil/problemer. Unntak oppstår under kjøring av programmet (runtime).
Typer C++-unntak
Det er to typer unntak i C++
- Synkron: Unntak som skjer når noe går galt på grunn av en feil i inndataene eller når programmet ikke er utstyrt for å håndtere gjeldende type data det jobber med, for eksempel å dele et tall med null.
- Asynkron : Unntak som er utenfor programmets kontroll, som diskfeil, tastaturavbrudd osv.
C++ prøv og fang
C++ gir en innebygd funksjon for unntakshåndtering. Det kan gjøres ved å bruke følgende spesialiserte nøkkelord: prøv, fang og kast med hvert sitt formål.
Syntaks for try-catch i 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. prøv i C++
Nøkkelordet try representerer en kodeblokk som kan gi et unntak plassert inne i try-blokken. Den etterfølges av en eller flere fangstblokker. Hvis et unntak oppstår, prøv å blokkere det unntaket.
2. fange i C++
Catch-setningen representerer en kodeblokk som utføres når et bestemt unntak blir kastet fra try-blokken. Koden for å håndtere unntaket er skrevet inne i catch-blokken.
3. kaste inn C++
Et unntak i C++ kan kastes ved å bruke søkeordet throw. Når et program møter en throw-setning, avslutter det umiddelbart gjeldende funksjon og begynner å finne en matchende catch-blokk for å håndtere det kastede unntaket.
Merk: Flere catch-setninger kan brukes til å fange opp forskjellige typer unntak som er kastet av try-blokk.
Nøkkelordene try and catch kommer i par: Vi bruker try-blokken for å teste noe kode, og hvis koden gir et unntak, vil vi håndtere det i catch-blokken vår.
Hvorfor trenger vi Unntakshåndtering i C++?
Følgende er hovedfordelene med unntakshåndtering fremfor tradisjonell feilhåndtering:
- Separasjon av feilhåndteringskode fra normal kode : Det er alltid if-else-betingelser for å håndtere feil i tradisjonelle feilhåndteringskoder. Disse forholdene og koden for å håndtere feil blandes sammen med den normale flyten. Dette gjør koden mindre lesbar og vedlikeholdbar. Med try/catch-blokker blir koden for feilhåndtering atskilt fra normal flyt.
- Funksjoner/metoder kan håndtere bare unntakene de velger : En funksjon kan gi mange unntak, men kan velge å håndtere noen av dem. De andre unntakene, som blir kastet, men ikke fanget opp, kan den som ringer håndtere. Hvis den som ringer velger å ikke fange dem, håndteres unntakene av den som ringer.
I C++ kan en funksjon spesifisere unntakene den kaster ved å bruke nøkkelordet throw. Den som ringer denne funksjonen må håndtere unntaket på en eller annen måte (enten ved å spesifisere det på nytt eller fange det).
- Gruppering av feiltyper : I C++ kan både grunnleggende typer og objekter kastes som unntak. Vi kan lage et hierarki av unntaksobjekter, gruppere unntak i navneområder eller klasser, og kategorisere dem i henhold til deres typer.
Eksempler på unntakshåndtering i C++
Følgende eksempler viser hvordan du bruker en try-catch-blokk for å håndtere unntak i C++.
Eksempel 1
Eksemplet nedenfor viser kaste-unntak i 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;> }> |
>
>Produksjon
Exception Division by zero not allowed!>
Eksempel 2
Følgende er et enkelt eksempel for å vise unntakshåndtering i C++. Utdataene fra programmet forklarer flyten av utførelse av try/catch-blokker.
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;> }> |
>
>Produksjon
Before try Inside try Exception Caught After catch (Will be executed)>
Egenskaper for unntakshåndtering i C++
Eiendom 1
Det er en spesiell catch-blokk kalt 'catch-all'-blokken, skrevet som catch(...), som kan brukes til å fange opp alle typer unntak.
Eksempel
I det følgende programmet blir en int kastet som et unntak, men det er ingen catch-blokk for int, så catch(...)-blokken vil bli utført.
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;> }> |
>
>
hvordan konvertere int til streng javaProduksjon
Default Exception>
Eiendom 2
Implisitt typekonvertering skjer ikke for primitive typer.
Eksempel
I det følgende programmet er 'a' ikke implisitt konvertert til int.
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;> }> |
>
>Produksjon
Default Exception>
Produksjon:
Default Exception>
Eiendom 3
Hvis et unntak blir kastet og ikke fanget opp noe sted, avsluttes programmet unormalt.
Eksempel
I det følgende programmet kastes en røye, men det er ingen fangstblokk for å fange røye.
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;> }> |
>
>
Produksjon
terminate called after throwing an instance of 'char'>
Vi kan endre denne unormale oppsigelsesadferden ved å skrive vår uventede funksjon.
Merk : Et avledet klasseunntak bør fanges opp før et grunnklasseunntak.
I likhet med Java har C++-biblioteket en standard unntak klasse som er basisklassen for alle standard unntak. Alle objekter som kastes av komponentene i standardbiblioteket er avledet fra denne klassen. Derfor kan alle standard unntak fanges opp ved å fange denne typen.
Eiendom 4
I motsetning til Java, i C++, er alle unntak avmerket, dvs. kompilatoren sjekker ikke om et unntak er fanget eller ikke (se dette for detaljer). Så det er ikke nødvendig å spesifisere alle ufangede unntak i en funksjonserklæring. Imidlertid er unntakshåndtering en anbefalt praksis å gjøre det.
Eksempel
hvor mange null for en million
Følgende program kompilerer fint, men ideelt sett bør signaturen til fun() vise de ukontrollerte unntakene.
CPP
// 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;> }> |
>
>
hvor stor er skjermen minProduksjon
Caught exception from fun()>
En bedre måte å skrive koden ovenfor på:
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;> }> |
>
>Produksjon
Caught exception from fun()>
Merk : Bruken av Dynamic Exception Specification har blitt avviklet siden C++11. En av grunnene til det kan være at det tilfeldig kan avbryte programmet ditt. Dette kan skje når du kaster et unntak av en annen type som ikke er nevnt i den dynamiske unntaksspesifikasjonen. Programmet ditt vil avbryte seg selv fordi det i det scenariet kaller (indirekte) terminate(), som som standard kaller abort().
Eiendom 5
I C++ kan try/catch-blokker nestes. Et unntak kan også kastes på nytt ved å bruke kast; .
Eksempel
Følgende program viser try/catch-blokker som hekker.
CPP
// 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;> }> |
>
>Produksjon
Handle Partially Handle remaining>
En funksjon kan også kaste en funksjon på nytt ved å bruke samme kast; syntaks. En funksjon kan håndtere en del og be den som ringer om å håndtere det resterende.
Eiendom 6
Når et unntak blir kastet, blir alle objekter som er opprettet inne i den omsluttende prøveblokken ødelagt før kontrollen overføres til catch-blokken.
Eksempel
Følgende program demonstrerer egenskapen ovenfor.
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;> >}> }> |
>
>
nettverk og typer nettverkProduksjon
Constructor of Test Destructor of Test Caught 10>
Begrensninger for unntakshåndtering i C++
Unntakshåndteringen i C++ har også få begrensninger:
- Unntak kan bryte strukturen eller flyten til koden ettersom flere usynlige utgangspunkter opprettes i koden som gjør koden vanskelig å lese og feilsøke.
- Hvis unntakshåndtering ikke gjøres riktig, kan det også føre til ressurslekkasjer.
- Det er vanskelig å lære å skrive unntakskode som er trygg.
- Det er ingen C++-standard for hvordan man bruker unntakshåndtering, derfor finnes det mange variasjoner i praksis for unntakshåndtering.
Konklusjon
Unntakshåndtering i C++ brukes til å håndtere uventede hendelser ved å bruke try and catch-blokker for å håndtere problemet effektivt. Denne unntakshåndteringen gjør programmene våre mer pålitelige ettersom feil under kjøring kan håndteres separat, og det bidrar også til å forhindre at programmet krasjer og brå avslutning av programmet når det oppstår feil.
Relaterte artikler:
- Topp C++ unntakshåndtering intervjuspørsmål og svar
- Quiz om unntakshåndtering i C++