logo

Gestione delle eccezioni in C++

In C++, le eccezioni sono anomalie di runtime o condizioni anomale che un programma incontra durante la sua esecuzione. Il processo di gestione di queste eccezioni è chiamato gestione delle eccezioni. Utilizzando il meccanismo di gestione delle eccezioni, il controllo da una parte del programma in cui si è verificata l'eccezione può essere trasferito a un'altra parte del codice.

Quindi, fondamentalmente, utilizzando la gestione delle eccezioni in C++, possiamo gestire le eccezioni in modo che il nostro programma continui a funzionare.



1 milione quanti 0

Cos'è un'eccezione C++?

Un'eccezione è un problema imprevisto che si verifica durante l'esecuzione di un programma, il nostro programma termina improvvisamente con alcuni errori/problemi. L'eccezione si verifica durante l'esecuzione del programma (runtime).

Tipi di eccezioni C++

Esistono due tipi di eccezioni in C++

  1. Sincrono: Eccezioni che si verificano quando qualcosa va storto a causa di un errore nei dati di input o quando il programma non è attrezzato per gestire il tipo di dati corrente con cui sta lavorando, come dividere un numero per zero.
  2. Asincrono : Eccezioni che esulano dal controllo del programma, come guasti del disco, interruzioni della tastiera, ecc.

C++ prova a catturare

C++ fornisce una funzionalità incorporata per la gestione delle eccezioni. Può essere fatto utilizzando le seguenti parole chiave specializzate: provare, prendere e lanciare, ognuna con uno scopo diverso.



Sintassi di try-catch in 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. prova in C++

La parola chiave try rappresenta un blocco di codice che può generare un'eccezione inserita all'interno del blocco try. È seguito da uno o più blocchi catch. Se si verifica un'eccezione, prova a bloccare che lancia quell'eccezione.

2. cattura in C++

L'istruzione catch rappresenta un blocco di codice che viene eseguito quando viene lanciata una particolare eccezione dal blocco try. Il codice per gestire l'eccezione è scritto all'interno del blocco catch.

3. inserisci C++

Un'eccezione in C++ può essere lanciata utilizzando la parola chiave Throw. Quando un programma incontra un'istruzione Throw, termina immediatamente la funzione corrente e inizia a cercare un blocco catch corrispondente per gestire l'eccezione lanciata.



Nota: È possibile utilizzare più istruzioni catch per rilevare diversi tipi di eccezioni generate dal blocco try.

Le parole chiave try e catch sono disponibili in coppia: utilizziamo il blocco try per testare del codice e se il codice genera un'eccezione, la gestiremo nel nostro blocco catch.

Perché ne abbiamo bisogno Gestione delle eccezioni in C++?

Di seguito sono riportati i principali vantaggi della gestione delle eccezioni rispetto alla gestione degli errori tradizionale:

  1. Separazione del codice di gestione degli errori dal codice normale : Esistono sempre condizioni if-else per gestire gli errori nei tradizionali codici di gestione degli errori. Queste condizioni e il codice per gestire gli errori vengono confusi con il flusso normale. Ciò rende il codice meno leggibile e manutenibile. Con i blocchi try/catch, il codice per la gestione degli errori diventa separato dal flusso normale.
  2. Le funzioni/metodi possono gestire solo le eccezioni scelte : Una funzione può generare molte eccezioni, ma può scegliere di gestirne alcune. Le altre eccezioni, che vengono lanciate ma non intercettate, possono essere gestite dal chiamante. Se il chiamante sceglie di non intercettarli, le eccezioni vengono gestite dal chiamante del chiamante.
    In C++, una funzione può specificare le eccezioni che genera utilizzando la parola chiave Throw. Il chiamante di questa funzione deve gestire l'eccezione in qualche modo (specificandola nuovamente o intercettandola).
  3. Raggruppamento di tipi di errore : In C++ sia i tipi base che gli oggetti possono essere lanciati come eccezioni. Possiamo creare una gerarchia di oggetti eccezione, raggruppare eccezioni in spazi dei nomi o classi e classificarle in base al loro tipo.

Esempi di gestione delle eccezioni in C++

Negli esempi seguenti viene illustrato come utilizzare un blocco try-catch per gestire le eccezioni in C++.

Esempio 1

L'esempio seguente mostra le eccezioni lanciate in 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;> }>

>

>

Produzione

Exception Division by zero not allowed!>

Esempio 2

Di seguito è riportato un semplice esempio per mostrare la gestione delle eccezioni in C++. L'output del programma spiega il flusso di esecuzione dei blocchi 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;> }>

qual è il file system di linux

>

>

Produzione

Before try Inside try Exception Caught After catch (Will be executed)>

Proprietà della gestione delle eccezioni in C++

Proprietà 1

Esiste uno speciale blocco catch chiamato blocco 'catch-all', scritto come catch(...), che può essere utilizzato per catturare tutti i tipi di eccezioni.

Esempio

Nel programma seguente, viene generato un int come eccezione, ma non esiste un blocco catch per int, quindi verrà eseguito il blocco 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;> }>

>

>

Produzione

Default Exception>

Proprietà 2

La conversione implicita del tipo non avviene per i tipi primitivi.

Esempio

Nel programma seguente, 'a' non viene convertito implicitamente in 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;> }>

>

>

Produzione

Default Exception>

Produzione:

Default Exception>

Proprietà 3

Se viene lanciata un'eccezione e non viene rilevata da nessuna parte, il programma termina in modo anomalo.

elenco doppiamente concatenato

Esempio

Nel programma seguente viene generato un carattere, ma non esiste alcun blocco catch per catturarlo.

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

>

>

Produzione

terminate called after throwing an instance of 'char'>

Possiamo modificare questo comportamento di terminazione anomalo scrivendo la nostra funzione inaspettata.

Nota : un'eccezione della classe derivata deve essere intercettata prima di un'eccezione della classe base.

Come Java, la libreria C++ ha un file eccezione standard class che è la classe base per tutte le eccezioni standard. Tutti gli oggetti lanciati dai componenti della libreria standard derivano da questa classe. Pertanto, tutte le eccezioni standard possono essere intercettate intercettando questo tipo.

Proprietà 4

A differenza di Java, in C++ tutte le eccezioni non sono controllate, cioè il compilatore non controlla se un'eccezione viene catturata o meno (vedi Questo per dettagli). Pertanto, non è necessario specificare tutte le eccezioni non rilevate in una dichiarazione di funzione. Tuttavia, la gestione delle eccezioni è una pratica consigliata per farlo.

Esempio

Il seguente programma viene compilato bene, ma idealmente la firma di fun() dovrebbe elencare le eccezioni non controllate.

CPP




impilare Java

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

>

>

Produzione

Caught exception from fun()>

Un modo migliore per scrivere il codice sopra:

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

>

>

Produzione

Caught exception from fun()>

Nota : L'uso della specifica delle eccezioni dinamiche è stato deprecato a partire da C++11. Uno dei motivi potrebbe essere che può interrompere in modo casuale il programma. Ciò può verificarsi quando si genera un'eccezione di un altro tipo che non è menzionata nella specifica dell'eccezione dinamica. Il tuo programma si interromperà da solo perché in quello scenario chiama (indirettamente) terminate(), che per impostazione predefinita chiama abort().

Proprietà 5

In C++, i blocchi try/catch possono essere annidati. Inoltre, un'eccezione può essere lanciata nuovamente utilizzando Throw; .

Esempio

Il seguente programma mostra l'annidamento dei blocchi try/catch.

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

javascript onclick
>

>

Produzione

Handle Partially Handle remaining>

Una funzione può anche rilanciare una funzione utilizzando lo stesso lancio; sintassi. Una funzione può gestire una parte e chiedere al chiamante di gestire la parte rimanente.

Proprietà 6

Quando viene lanciata un'eccezione, tutti gli oggetti creati all'interno del blocco try che lo racchiude vengono distrutti prima che il controllo venga trasferito al blocco catch.

Esempio

Il seguente programma dimostra la proprietà di cui sopra.

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

>

>

Produzione

Constructor of Test Destructor of Test Caught 10>

Limitazioni della gestione delle eccezioni in C++

Anche la gestione delle eccezioni in C++ presenta alcune limitazioni:

  • Le eccezioni possono interrompere la struttura o il flusso del codice poiché nel codice vengono creati più punti di uscita invisibili che rendono difficile la lettura e il debug del codice.
  • Se la gestione delle eccezioni non viene eseguita correttamente può portare anche a perdite di risorse.
  • È difficile imparare a scrivere un codice di eccezione che sia sicuro.
  • Non esiste uno standard C++ su come utilizzare la gestione delle eccezioni, quindi esistono molte variazioni nelle pratiche di gestione delle eccezioni.

Conclusione

La gestione delle eccezioni in C++ viene utilizzata per gestire eventi imprevisti utilizzando i blocchi try and catch per gestire il problema in modo efficiente. Questa gestione delle eccezioni rende i nostri programmi più affidabili poiché gli errori in fase di esecuzione possono essere gestiti separatamente e aiuta anche a prevenire l'arresto anomalo del programma e l'interruzione improvvisa del programma quando si verifica un errore.

Articoli Correlati:

  • Domande e risposte principali sull'intervista sulla gestione delle eccezioni C++
  • Quiz sulla gestione delle eccezioni in C++