use*_*424 35 c++ exception-handling
当我尝试除以0时,下面的代码没有捕获异常.我是否需要抛出异常,或者计算机是否在运行时自动抛出一个异常?
int i = 0;
cin >> i; // what if someone enters zero?
try {
i = 5/i;
}
catch (std::logic_error e) {
cerr << e.what();
}
Run Code Online (Sandbox Code Playgroud)
pax*_*blo 58
您需要自己检查并抛出异常.整数除以零在标准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;
}
Run Code Online (Sandbox Code Playgroud)
你会认为这overflow_error
对于表示除以零是理想的.
但是domain_error
(5.6
虽然我认为这与先前的迭代没有改变)部分明确指出:
如果
C++11
或的第二个操作数/
为零,则行为未定义.
因此,它可能抛出该(或任何其他)异常.它还可以格式化您的硬盘并嘲笑地笑:-)
如果你想实现这样的野兽,你可以使用类似于%
以下程序的东西:
#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;
}
Run Code Online (Sandbox Code Playgroud)
这输出:
5
Divide by zero exception -> 5
Run Code Online (Sandbox Code Playgroud)
并且您可以看到它抛出并捕获除零除外的情况.
该intDivEx
等效几乎是一模一样的:
// 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;
}
Run Code Online (Sandbox Code Playgroud)
Tom*_*Tom 18
更新了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();
}
}
Run Code Online (Sandbox Code Playgroud)
这将设置一个新的信号处理程序,它抛出一个异常,并设置一个shared_ptr
旧的信号处理程序,它带有一个自定义的"删除"功能,可以在旧的处理程序超出范围时恢复它.
您需要至少使用以下选项进行编译:
g++ -c Foo.cc -o Foo.o -fnon-call-exceptions -std=c++11
Run Code Online (Sandbox Code Playgroud)
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();
}
}
Run Code Online (Sandbox Code Playgroud)
当然,您可以跳过所有C++ 11-ishness,并将它们放在传统的RAII管理结构中.
据我所知,C++规范没有提及除零除外的任何内容.我相信你需要自己做...
Stroustrup在"C++的设计和演变"(Addison Wesley,1994)中说,"低级事件,例如算术溢出和除以零,假定由专用的低级机制而不是异常处理这使C++在算术运算时能够匹配其他语言的行为.它还避免了在流水线严重的体系结构中出现的问题,其中除以零之类的事件是异步的."