C++ 捕获异常:除以零

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6121623/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 19:31:28  来源:igfitidea点击:

Catching exception: divide by zero

c++exception-handling

提问by user33424

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?

下面的代码在我尝试除以 0 时没有捕获异常。我需要抛出异常,还是计算机在运行时自动抛出异常?

int i = 0;

cin >> i;  // what if someone enters zero?

try {
    i = 5/i;
}
catch (std::logic_error e) {

    cerr << e.what();
}

回答by paxdiablo

You need to check it yourself and throw an exception. Integer divide by zero is not an exception in standard C++.

您需要自己检查并抛出异常。整数除以零在标准 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:

ISO 标准中列出的例外情况是:

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 isa problem with the input value) would be ideal for indicating a divide by zero.

并且您可以很有说服力地争辩说overflow_error(由 IEEE754 浮点生成的无穷大可以被视为溢出)或domain_error(这输入值的问题)对于指示除以零是理想的。

However, section 5.6(of C++11, though I don't think this has changed from the previous iteration) specifically states:

但是,5.6(of C++11,尽管我认为这与上一次迭代相比没有改变)特别指出:

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

如果/or的第二个操作数%为零,则行为未定义。

So, it couldthrow 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 intDivExin the following program (using the overflow variant):

如果你想实现这样的野兽,你可以intDivEx在下面的程序中使用类似的东西(使用溢出变体):

#include <iostream>
#include <stdexcept>

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

This outputs:

这输出:

5
Divide by zero exception -> 5

and you can see it throws and catches the exception for the divide by zero case.

您可以看到它抛出并捕获除以零的异常情况。



The %equivalent is almost exactly the same:

%等效几乎是一模一样的:

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

回答by Tom

Updated with comments from ExcessPhase

更新了来自 ExcessPhase 的评论

GCC (at least version 4.8) will let you emulate this behaviour:

GCC(至少 4.8 版)将让您模拟这种行为:

#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_ptrto the old signal handler, with a custom 'deletion' function that restores the old handler when it goes out of scope.

这会设置一个抛出异常的新信号处理程序,并设置一个shared_ptr旧信号处理程序,并使用自定义“删除”函数在旧处理程序超出范围时恢复旧处理程序。

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:

Visual C++ 也可以让你做类似的事情:

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

当然,您可以跳过所有与 C++11 相关的内容,并将它们放入传统的 RAII 管理结构中。

回答by Mayank

As far as I know C++ specifications does not mention anything about divide by zero exeption. I believe you need to do it yourself...

据我所知,C++ 规范没有提到除以零例外的任何内容。我相信你需要自己做...

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

Stroustrup 说,在“C++ 的设计和演化”(Addison Wesley,1994 年)中,“低级事件,例如算术溢出和被零除,被假定由专用的低级机制而不是异常处理。这使 C++ 在算术方面能够匹配其他语言的行为。它还避免了在大量流水线架构上发生的问题,其中诸如除以零之类的事件是异步的。”`

回答by yask

You need to throw the exception manually using throwkeyword.

您需要使用throw关键字手动抛出异常。

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

回答by Vadiklk

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

你应该检查是否i = 0然后不分开。

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

(可选地,在检查之后,您可以抛出异常并稍后处理)。

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

更多信息请访问:http: //www.cprogramming.com/tutorial/exceptions.html

回答by iammilind

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

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

Either you need to throwthe exception yourself and catchit. e.g.

要么你需要throw自己和catch它的例外。例如

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

Or catchthe exception which is thrown by your code.

或者catch您的代码抛出的异常。

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 meantfor divide by zero. If there is no such exception then you can use,

在你的情况,我不知道是否有任何标准异常意味着零的鸿沟。如果没有这样的例外,那么你可以使用,

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

回答by fons haffmans

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.

你可以做assert(2 * i != i)这将抛出一个断言。如果您需要更高级的东西,您可以编写自己的异常类。