Catching Exception: Divide by Zero

Catching exception: divide by zero

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:

exception catching for int divided by 0

Any integer when divided by zero is not an exception in standard C++.

The section 5.6 of C++ states:

If the second operand of / or % is zero, the behavior is undefined.

You may also find it interesting to read this:

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."`

C++ : Catch a divide by zero error

It's not an exception. It's an error which is determined at hardware level and is returned back to the operating system, which then notifies your program in some OS-specific way about it (like, by killing the process).

I believe that in such case what happens is not an exception but a signal. If it's the case: The operating system interrupts your program's main control flow and calls a signal handler, which - in turn - terminates the operation of your program.

It's the same type of error which appears when you dereference a null pointer (then your program crashes by SIGSEGV signal, segmentation fault).

You could try to use the functions from <csignal> header to try to provide a custom handler for the SIGFPE signal (it's for floating point exceptions, but it might be the case that it's also raised for integer division by zero - I'm really unsure here). You should however note that the signal handling is OS-dependent and MinGW somehow "emulates" the POSIX signals under Windows environment.


Here's the test on MinGW 4.5, Windows 7:

#include <csignal>
#include <iostream>

using namespace std;

void handler(int a) {
cout << "Signal " << a << " here!" << endl;
}

int main() {
signal(SIGFPE, handler);
int a = 1/0;
}

Output:

Signal 8 here!

And right after executing the signal handler, the system kills the process and displays an error message.

Using this, you can close any resources or log an error after a division by zero or a null pointer dereference... but unlike exceptions that's NOT a way to control your program's flow even in exceptional cases. A valid program shouldn't do that. Catching those signals is only useful for debugging/diagnosing purposes.

(There are some useful signals which are very useful in general in low-level programming and don't cause your program to be killed right after the handler, but that's a deep topic).

Why doesn't 'd /= d' throw a division by zero exception when d == 0?

C++ does not have a "Division by Zero" Exception to catch. The behavior you're observing is the result of Compiler optimizations:

  1. The compiler assumes Undefined Behavior doesn't happen
  2. Division by Zero in C++ is undefined behavior
  3. Therefore, code which can cause a Division by Zero is presumed to not do so.

    • And, code which must cause a Division by Zero is presumed to never happen
  4. Therefore, the compiler deduces that because Undefined Behavior doesn't happen, then the conditions for Undefined Behavior in this code (d == 0) must not happen
  5. Therefore, d / d must always equal 1.

However...

We can force the compiler to trigger a "real" division by zero with a minor tweak to your code.

volatile int d = 0;
d /= d; //What happens?

So now the question remains: now that we've basically forced the compiler to allow this to happen, what happens? It's undefined behavior—but we've now prevented the compiler from optimizing around this undefined behavior.

Mostly, it depends on the target environment. This will not trigger a software exception, but it can (depending on the target CPU) trigger a Hardware Exception (an Integer-Divide-by-Zero), which cannot be caught in the traditional manner a software exception can be caught. This is definitely the case for an x86 CPU, and most other (but not all!) architectures.

There are, however, methods of dealing with the hardware exception (if it occurs) instead of just letting the program crash: look at this post for some methods that might be applicable: Catching exception: divide by zero. Note they vary from compiler to compiler.

How to catch divide-by-zero error in Visual Studio 2008 C++?

Assuming that you can't simply fix the cause of the exception generating code (perhaps because you don't have the source code to that particular library and perhaps because you can't adjust the input params before they cause a problem).

You have to jump through some hoops to make this work as you'd like but it can be done.

First you need to install a Structured Exception Handling translation function by calling _set_se_translator() (see here) then you can examine the code that you're passed when an SEH exception occurs and throw an appropriate C++ exception.

void CSEHException::Translator::trans_func(
unsigned int code,
EXCEPTION_POINTERS *pPointers)
{
switch (code)
{
case FLT_DIVIDE_BY_ZERO :
throw CMyFunkyDivideByZeroException(code, pPointers);
break;
}

// general C++ SEH exception for things we don't need to handle separately....
throw CSEHException(code, pPointers);
}

Then you can simply catch your CMyFunkyDivideByZeroException() in C++ in the normal way.

Note that you need to install your exception translation function on every thread that you want exceptions translated.

C++ -- Catching built-in divide by zero exception

The notation you're using to interpret complex operations, doesn't change the way you're doing your low-level operations - like division. Somewhere in your code you have to perform a simple x/y and in that place, when you know you're gonna divide, check for 0:

if(y==0)
// your error handling goes here, maybe simple y=1
stack.pushBack(x/y);

Note that in C++ a division by 0 isn't really an exception. Quoting Stroustrup - the creator of the language:

"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."

In your case:

if(nextChar == '/') {
input.get();
T x = eval(input);
T y = eval(input);

if(!y) handlingTheVeryDifficultSituation();
return x/y;
}


Related Topics



Leave a reply



Submit