提问者:小点点

捕获异常:被零除


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

int i = 0;

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

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

    cerr << e.what();
}

共3个答案

匿名用户

您需要自己检查它并抛出异常。 整数被零除在标准C++中不是一个例外。

浮点也不能被零除,但至少它有特定的处理方法。

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

您可以非常令人信服地认为,overflow_error(由IEEE754浮点生成的无穷大可以被认为是溢出)或domain_error(这是输入值的一个问题)对于指示除零是理想的。

然而,5.6(C++11的部分,尽管我认为这与上一次迭代没有变化)特别指出:

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

因此,它可以抛出这些(或任何其他)异常。 它还可以格式化你的硬盘,嘲笑你:-)

如果您想实现这样的beast,可以在以下程序中使用类似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;
}

此输出:

5
Divide by zero exception -> 5

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

等效的%几乎完全相同:

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

匿名用户

使用ExcessPhase中的注释更新

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

这将设置一个抛出异常的新信号处理程序和一个shared_ptr到旧信号处理程序,并使用一个自定义的“deletion”函数在旧处理程序超出作用域时还原旧处理程序。

您至少需要使用以下选项进行编译:

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

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

当然,你可以跳过所有的C++11,把它们放到一个传统的rai-management结构中。

匿名用户

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

Stroustrup在《the Design and Evolution of C++》(Addison Wesley,1994)中说:“低级事件,如算术溢出和除零,被认为是由一个专用的低级机制而不是由异常来处理的。这使得C++在涉及算术时能够匹配其他语言的行为。它还避免了在严重流水线结构中发生的问题,其中除零等事件是异步的。”