Catching exception: divide by zero
The following code does not catch an exception, when I try to divide by 0. Do I need to throw an exception, or does the computer automatically throw one at runtime?
int i = 0;
cin >> i; // what if someone enters zero?
try {
i = 5/i;
}
catch (std::logic_error e) {
cerr << e.what();
}
Solution 1:
You need to check it yourself and throw an exception. Integer divide by zero is not an exception in standard C++.
Neither is floating point divide by zero but at least that has specific means for dealing with it.
The exceptions listed in the ISO standard are:
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;
}
and you could argue quite cogently that either overflow_error
(the infinity generated by IEEE754 floating point could be considered overflow) or domain_error
(it is a problem with the input value) would be ideal for indicating a divide by zero.
However, section 5.6
(of C++11
, though I don't think this has changed from the previous iteration) specifically states:
If the second operand of
/
or%
is zero, the behavior is undefined.
So, it could throw those (or any other) exceptions. It could also format your hard disk and laugh derisively :-)
If you wanted to implement such a beast, you could use something like intDivEx
in the following program (using the overflow variant):
#include <iostream>
#include <stdexcept>
// Integer division/remainder, 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;
}
inline int intModEx (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, 0); }
catch (std::overflow_error &e) {
std::cout << e.what() << " -> ";
}
std::cout << i << std::endl;
try { i = intDivEx (10, 2); }
catch (std::overflow_error &e) {
std::cout << e.what() << " -> ";
}
std::cout << i << std::endl;
return 0;
}
This outputs:
Divide by zero exception -> 42
5
and you can see it throws and catches the exception (leaving the return variable untouched) for the divide by zero case.
The %
equivalent is almost exactly the same:
Solution 2:
Updated with comments from ExcessPhase
GCC (at least version 4.8) will let you emulate this behaviour:
#include <signal.h>
#include <memory>
#include <iostream>
int main() {
std::shared_ptr<void(int)> 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();
}
}
This sets up a new signal handler which throws an exception, and a shared_ptr
to the old signal handler, with a custom 'deletion' function that restores the old handler when it goes out of scope.
You need to compile with at least these options:
g++ -c Foo.cc -o Foo.o -fnon-call-exceptions -std=c++11
Visual C++ will also let you do something similar:
#include <eh.h>
#include <memory>
int main() {
std::shared_ptr<void(unsigned, EXCEPTION_POINTERS*)> handler(
_set_se_translator([](unsigned u, EXCEPTION_POINTERS* p) {
switch(u) {
case FLT_DIVIDE_BY_ZERO:
case INT_DIVIDE_BY_ZERO:
throw std::logic_error("Divide by zero");
break;
...
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();
}
}
And of course you can skip all the C++11-ishness of this and put them in a traditional RAII-managing struct.
Solution 3:
As far as I know C++ specifications does not mention anything about divide by zero exeption. I believe you need to do it yourself...
Stroustrup says, in "The Design and Evolution of C++" (Addison Wesley, 1994), "low-level events, such as arithmetic overflows and divide by zero, are assumed to be handled by a dedicated lower-level mechanism rather than by exceptions. This enables C++ to match the behaviour of other languages when it comes to arithmetic. It also avoids the problems that occur on heavily pipelined architectures where events such as divide by zero are asynchronous."`