Catching exception: divide by zero

C++Exception Handling

C++ Problem Overview


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

C++ Solutions


Solution 1 - C++

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 - C++

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 - C++

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

Solution 4 - C++

You should check if i = 0 and not divide then.

(Optionally after checking it you can throw an exception and handle it later).

More info at: http://www.cprogramming.com/tutorial/exceptions.html

Solution 5 - C++

You need to throw the exception manually using throw keyword.

Example:

#include <iostream>
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;
}

Solution 6 - C++

setjmp + longjmp

https://stackoverflow.com/a/25601100/895245 mentioned the possibility or throwing a C++ exception from a signal handler, but https://stackoverflow.com/questions/1717991/throwing-an-exception-from-within-a-signal-handler mentions several caveats of that, so I would be very careful.

As another potentially dangerous possibility, you can also try to use the older C setjmp + longjmp mechanism as shown at: https://stackoverflow.com/questions/39431879/c-handle-signal-sigfpe-and-continue-execution/39431923#39431923

main.cpp

#include <csetjmp>
#include <csignal>
#include <cstring>
#include <iostream>

jmp_buf fpe;

void handler(int signum) {
    longjmp(fpe, 1);
}

int main() {
    volatile int i, j;
    for(i = 0; i < 10; i++) {
        struct sigaction act;
        struct sigaction oldact;
        memset(&act, 0, sizeof(act));
        act.sa_handler = handler;
        act.sa_flags = SA_NODEFER | SA_NOMASK;
        sigaction(SIGFPE, &act, &oldact);
        if (0 == setjmp(fpe)) {
            std::cout << "before divide" << std::endl;
            j = i / 0;
            sigaction(SIGFPE, &oldact, &act);
        } else {
            std::cout << "after longjmp" << std::endl;
            sigaction(SIGFPE, &oldact, &act);
        }
    }
    return 0;
}

Compile and run:

g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out

Output:

i = 0
before divide
after longjmp
i = 1
before divide
after longjmp
i = 2
before divide
after longjmp

man longjmp says that you can longjmp from signal handlers, but with a few caveats:

> POSIX.1-2008 Technical Corrigendum 2 adds longjmp() and siglongjmp() to the list of async-signal-safe functions. However, the standard recommends avoiding the use of these functions from signal handlers and goes on to point out that if these functions are called from a signal handler that interrupted a call to a non-async-signal-safe function (or some equivalent, such as the steps equivalent to exit(3) that occur upon a return from the initial call to main()), the behavior is undefined if the program subsequently makes a call to a non-async-signal-safe function. The only way of avoiding undefined behavior is to ensure one of the following: > > * After long jumping from the signal handler, the program does not call any non-async-signal-safe functions and does not return from the initial call to main(). > > * Any signal whose handler performs a long jump must be blocked during every call to a non-async-signal-safe function and no non-async-signal-safe functions are called after returning from the initial call to main().

See also: https://stackoverflow.com/questions/7334595/longjmp-out-of-signal-handler

However https://stackoverflow.com/questions/1717991/throwing-an-exception-from-within-a-signal-handler/26948383#comment55176895_26948383 mentions that this has further dangers with C++:

> setjmp and longjmp aren't compatible with exceptions and RAII (ctors/dtors), though. :( You'll probably get resource leaks with this.

so you would have to be very very careful with that as well.

I guess the moral is that signal handlers are hard, and you should avoid them as much as possible unless you know exactly what you are doing.

Detect floating point zero division

It is also possible to detect floating point division by zero with a glibc call to:

#include <cfenv>

feenableexcept(FE_INVALID);

as shown at: https://stackoverflow.com/questions/18118408/what-is-difference-between-quiet-nan-and-signaling-nan/55648118#55648118

This makes it raises SIGFPE as well like the integer division by zero instead of just silently qnan and setting flags.

Solution 7 - C++

What about this one? Tested with Clang, GCC throws SIGILL.

#include <iostream>
#include <cassert>

int main()
{
    unsigned int x = 42;
    unsigned int y = x;
    y -= x;
    x /= y;
    
    std::cout << x << " != "<< *(&x) << std::endl;
    assert (*(&x) == x);
}

Solution 8 - C++

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

Either you need to throw the exception yourself and catch it. e.g.

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

Or catch the exception which is thrown by your code.

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

In your case, I am not sure if is there any standard exception meant for divide by zero. If there is no such exception then you can use,

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

Solution 9 - C++

You can just do assert(2 * i != i) which will throw an assert. You can write your own exception class if you need something fancier.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser33424View Question on Stackoverflow
Solution 1 - C++paxdiabloView Answer on Stackoverflow
Solution 2 - C++TomView Answer on Stackoverflow
Solution 3 - C++MayankView Answer on Stackoverflow
Solution 4 - C++VadiklkView Answer on Stackoverflow
Solution 5 - C++yaskView Answer on Stackoverflow
Solution 6 - C++Ciro Santilli Путлер Капут 六四事View Answer on Stackoverflow
Solution 7 - C++damkratView Answer on Stackoverflow
Solution 8 - C++iammilindView Answer on Stackoverflow
Solution 9 - C++fons haffmansView Answer on Stackoverflow