2011-05-25 96 views
27

當我嘗試除以0時,以下代碼未捕獲到異常。我是否需要拋出異常,還是計算機在運行時自動拋出一個異常?捕捉異常:除以零

int i = 0; 

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

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

    cerr << e.what(); 
} 
+9

爲什麼不檢查wheter'i'是否爲零? – Nick 2011-05-25 08:34:54

+11

你爲什麼要試圖用ze- ** OH SHI分開 - ** – BoltClock 2011-05-25 08:35:30

+0

不,不是真的,我編輯了我的問題。 – user33424 2011-05-25 08:40:18

回答

45

你需要自己檢查並拋出異常。標準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將是理想的零指示鴻溝。

5.6部分(的C++11,但我不認爲這已經從先前的迭代變化)明確規定:

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

所以,可能拋出(或任何其他)例外。它也可以格式化你的硬盤,笑嘲弄:-)


如果你想實現這樣一個東西,你可以在下面的程序使用類似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; 
} 
+0

謝謝,我正在尋找系統拋出異常的情況下,這些可能在c + +? – user33424 2011-05-25 08:43:31

+1

@ user33424,是的,這是可能的,看到我的答案例如'新' – iammilind 2011-05-25 08:46:26

+0

HMMM拋出'std :: bad_alloc',所以你不必小心選擇,當你決定使用異常類,因爲他們都採取相同的參數。 – user33424 2011-05-25 09:09:25

7

據我瞭解C++規範不以零exeption提過任何鴻溝。我相信你需要自己做...

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

-2

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

要麼你需要自己和catchthrow例外。例如

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

catch您的代碼拋出的異常。

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

在你的情況,如果有任何標準異常零的意思的鴻溝我不知道。如果不存在這樣的異常,那麼你可以使用,

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

用零除是未定義的行爲。 – GManNickG 2011-05-25 08:52:30

+0

人不知道這個特性是否存在(在Windows中超過20年的時間和OSX)不應該在這裏回答,也不應該投票或者自稱軟件工程師。 – 2016-03-01 17:45:07

-3

你可以做assert(2 * i != i)這將拋出一個斷言。如果你需要更奇特的東西,你可以編寫自己的例外課。

+1

-1我真的不喜歡這個解決方案。這比'assert(i!= 0)'更容易嗎?我沒有想過通過邊界案例,但如果看到一個斷言被正確地陳述並不是微不足道的,那麼你就不應該這麼做。 – kay 2012-07-14 23:09:13

+0

另外,由於存在'NDEBUG','assert'經常在生產代碼中被禁用--' assert()'通常是一個用於捕獲問題的開發專用方法。在任何情況下,拋出一個斷言是*不是*拋出異常。前者會中止你的程序,而不會產生你能捕獲的東西。 – paxdiablo 2015-11-03 01:47:23

9

從ExcessPhase

GCC(版本至少爲4.8)與評論更新將讓你模仿這種行爲:

#include <signal.h> 
#include <memory> 

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; 

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

    try { 
     i = 5/i; 
    } 
    catch (std::logic_error e) { 
     std::cerr << e.what(); 
    } 
} 

這將設置其拋出異常的新的信號處理程序,一個shared_ptr添加到舊的信號處理程序中,並具有自定義的「刪除」功能,可在舊的處理程序超出範圍時恢復它。

你需要有至少這些選項編譯:

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: 
        throw std::logic_error("Divide by zero"); 
       ... 
       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這一點,並把它們放在一個傳統的RAII管理結構中。

+0

設置和恢復信號處理程序應使用RAII!你也不能假設,默認的信號處理程序是你暫時替換的信號處理程序。 – 2015-11-03 17:46:47

+0

謝謝@ExcessPhase,我已經更新了答案以反映這一點。 – Tom 2016-02-23 14:35:04

+0

在Visual Studio 2012中編譯visual C++代碼時,出現此錯誤:「FLT_DIVIDE_BY_ZERO:未聲明的標識符」。我已經包含了「windows.h」。我哪裏錯了? – Nishant 2016-07-15 04:10:36

0

您需要使用throw關鍵字手動拋出異常。

例子:

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