Eccezione di cattura: dividi per zero

Il seguente codice non cattura un’eccezione, quando provo a dividere per 0. Devo lanciare un’eccezione o il computer ne lancia automaticamente uno in fase di runtime?

int i = 0; cin >> i; // what if someone enters zero? try { i = 5/i; } catch (std::logic_error e) { cerr << e.what(); } 

Devi controllarlo tu stesso e fare un’eccezione. La divisione intera per zero non è un’eccezione nello standard C ++.

Né la divisione in virgola mobile si divide per zero, ma almeno quella ha i mezzi specifici per affrontarla.

Le eccezioni elencate nello standard ISO sono:

 namespace std { class logic_error; class domain_error; class invalid_argument; class length_error; class out_of_range; class runtime_error; class range_error; class overflow_error; class underflow_error; } 

e si potrebbe pensare che overflow_error sarebbe l’ideale per indicare una divisione per zero.

Ma la sezione 5.6 (di C++11 , anche se non penso che questo sia cambiato rispetto alla precedente iterazione) afferma in particolare:

Se il secondo operando di / o % è zero, il comportamento non è definito.

Quindi, potrebbe lanciare quell’eccezione (o qualsiasi altra). Potrebbe anche formattare il tuo disco rigido e ridere in modo derisorio 🙂


Se volessi implementare una tale bestia, potresti usare qualcosa come intDivEx nel seguente programma:

 #include  #include  // Integer division, catching divide by zero. inline int intDivEx (int numerator, int denominator) { if (denominator == 0) throw std::overflow_error("Divide by zero exception"); return numerator / denominator; } int main (void) { int i = 42; try { i = intDivEx (10, 2); } catch (std::overflow_error e) { std::cout < < e.what() << " -> "; } std::cout < < i << std::endl; try { i = intDivEx (10, 0); } catch (std::overflow_error e) { std::cout << e.what() << " -> "; } std::cout < < i << std::endl; return 0; } 

Questo produce:

 5 Divide by zero exception -> 5 

e puoi vederlo lanciare e catturare l'eccezione per il caso di divisione per zero.


L'equivalente % è quasi esattamente lo stesso:

 // Integer remainder, catching divide by zero. inline int intModEx (int numerator, int denominator) { if (denominator == 0) throw std::overflow_error("Divide by zero exception"); return numerator % denominator; } 

Aggiornato con commenti da ExcessPhase

GCC (almeno versione 4.8) ti consente di emulare questo comportamento:

 #include  #include  #include  int main() { std::shared_ptr handler( signal(SIGFPE, [](int signum) {throw std::logic_error("FPE"); }), [](__sighandler_t f) { signal(SIGFPE, f); }); int i = 0; std::cin >> i; // what if someone enters zero? try { i = 5/i; } catch (std::logic_error e) { std::cerr < < e.what(); } } 

Questo imposta un nuovo gestore di segnale che genera un'eccezione e un shared_ptr al vecchio gestore di segnale, con una funzione di 'cancellazione' personalizzata che ripristina il vecchio gestore quando esce dall'ambito.

Devi compilare almeno con queste opzioni:

 g++ -c Foo.cc -o Foo.o -fnon-call-exceptions -std=c++11 

Visual C ++ ti consente anche di fare qualcosa di simile:

 #include  #include  int main() { std::shared_ptr handler( _set_se_translator([](unsigned u, EXCEPTION_POINTERS* p) { switch(u) { case FLT_DIVIDE_BY_ZERO: throw std::logic_error("Divide by zero"); ... default: throw std::logic_error("SEH exception"); } }), [](_se_translator_function f) { _set_se_translator(f); }); int i = 0; try { i = 5 / i; } catch(std::logic_error e) { std::cerr < < e.what(); } } 

E ovviamente puoi saltare tutta l'11-ishness del C ++ e metterli in una struttura tradizionale di gestione RAII.

Per quanto ne so, le specifiche C ++ non menzionano nulla sull’eccezione da zero. Credo che tu abbia bisogno di farlo da solo …

Stroustrup dice, in “The Design and Evolution of C ++” (Addison Wesley, 1994), “gli eventi di basso livello, come gli overflow aritmetici e la divisione per zero, sono considerati gestiti da un meccanismo dedicato di livello inferiore piuttosto che da eccezioni Ciò consente al C ++ di eguagliare il comportamento di altri linguaggi quando si tratta di operazioni aritmetiche, evitando anche i problemi che si verificano su architetture con pipeline pesante dove eventi come divide per zero sono asincroni. ”

Dovresti controllare se i = 0 e non dividere poi.

(Opzionalmente dopo averlo controllato puoi lanciare un’eccezione e gestirla in un secondo momento).

Maggiori informazioni su: http://www.cprogramming.com/tutorial/exceptions.html

Devi lanciare l’eccezione manualmente usando la parola chiave throw .

Esempio:

 #include  using namespace std; double division(int a, int b) { if( b == 0 ) { throw "Division by zero condition!"; } return (a/b); } int main () { int x = 50; int y = 0; double z = 0; try { z = division(x, y); cout < < z << endl; }catch (const char* msg) { cerr << msg << endl; } return 0; } 

do i need to throw an exception or does the computer automatically throws one at runtime?

O hai bisogno di throw l’eccezione te stesso e catch . per esempio

 try { //... throw int(); } catch(int i) { } 

O catch l’eccezione che viene lanciata dal tuo codice.

 try { int *p = new int(); } catch (std::bad_alloc e) { cerr < < e.what(); } 

Nel tuo caso, non sono sicuro se ci sia qualche eccezione standard per dividere per zero. Se non esiste tale eccezione, puoi usare,

 catch(...) { // catch 'any' exception } 

Puoi semplicemente fare assert(2 * i != i) che genererà un assert. Puoi scrivere la tua class di eccezione se hai bisogno di qualcosa di più bello.