std :: istream运算符异常重置/不抛出 [英] std::istream operator exception reset / not thrown
问题描述
我不确定如何使用 std :: istream :: exception
(根据标准),让 std :: istream :: operator>>
如果不能将输入读入变量,则抛出异常,例如双。
下面的代码与clang / libc ++和gcc / libstdc ++有不同的行为:
#include< iostream>
#include< cassert>
int main(){
double foo,bar;
std :: istream& is = std :: cin;
is.exceptions(std :: istream :: failbit);
是>> foo; // throws exception as expected with gcc / libstdc ++ with inputASD
std :: cout<< foo;
是>>酒吧;
std :: cout<<酒吧;
assert(is); //输入ASD后,clang / libc ++失败
std :: cout< foo< < bar<< std :: endl;
}
是 is.exceptions :: istream :: failbit);
根据C ++标准,为了让 operator>>
首先介绍一些背景信息(如果您需要进一步阐述,下面将分别解释它们各自的标题):
- 当
istream
才能重新创建 > ios_base :: badbit 设置在basic_istream :: exceptions
- libstdc ++不符合此要求但libc ++确实
- libc ++无效请求其反映libstdc ++行为的错误
- libc ++ proffers
ios_base :: badbit
与所需的ios_base :: iostate
一起作为解决方法使用。
不幸的是,每当 ios_base :: badbit
设置独立于 ios_base :: failbit $ c $时,此解决方法也会产生副作用c>: http://en.cppreference.com/w/cpp/ io / ios_base / iostate#The_badbit
如果您在 > ios_base :: failbit
设置,你需要这个在libc ++和libstdc ++上有相同的行为,你必须检查 ios_base :: badbit
在 istream
上发生每个输入操作后。这需要看起来像这样:
if(is.rdstate()& ios_base :: failbit!= 0 )throw ios_base :: failure(basic_ios :: clear);
如cpplearner指出的,你甚至不能使用 basic_istream :: fail
,你必须对 istream
的 rdstate
return。
这可能是一个巨大的任务,是 istream的范围
。 istream
的广泛使用可以通过辅助函数,但使用 istream_iterator
s或提取运算符的复合重载很快就手动检查这个不合理的任务。
如果你发现自己在那里,我会认真考虑 is.exceptions(ios_base :: failbit | ios_base :: badbit)
解决方法。
code> ios_base :: badbit 设置在 basic_istream中时,$ c> istream
才能重新引用 :: exceptions
调用 basic_istream :: exceptions(istream :: failbit)
设置一个可以通过调用 basic_istream :: exceptions()
检索的掩码,根据标准的27.5.5.4 [iosstate.flags] / 11:
确定
rdstate()
中设置的元素会导致异常抛出的掩码。 p>
在27.7.2.2.3 [istream :: extractors] / 15中支持未格式化的插入方法:
如果没有插入任何字符,因为它从
* 和<$ c $在
,则重新抛出捕获的异常。exceptions()
(27.5.5.4)中启用了c> failbit
然而,对于格式化的输入,这是在27.7.2.2.1 [istream.formatted.reqmts] / 1;只有当位和位掩码和 ios_base :: badbit
不为零时才需要抛出:
如果在输入期间抛出异常,
ios :: badbit
会在* this
的错误状态。如果(exceptions()& badbit)!= 0
,则异常被重新引用。
$ b b
libstdc ++不符合此要求,但libc ++不符合
ios_base ::对于以下事件,应在
: istream
上设置failbit
basic_istream :: operator>>
的数字,指针和布尔输入重载(技术上,num_get ::
$ b $
$ b[来源]
如果只有 ios_base :: failbit
设置在 basic_istream :: exceptions
'掩码并且发生事件,使得设置 ios_base :: failbit
,例如如上所述提取无效数字:
- 在libstdc ++ 下还有一个异常不符合标准
- 在libc ++下没有这样的异常被抛出,意味着标准被支持
libc ++无效请求它镜像libstdc ++行为的错误
有一个现在无效的bug libc ++ 这个问题。引用27.7.2.1 [istream] / 4
如果这些被调用的函数中有一个抛出异常,在错误状态下设置
badbit
。如果exceptions()
中的badbit
打开,则输入函数重新抛出异常而不完成其操作,否则不会抛出任何内容并继续处理,就像被调用函数返回失败指示一样。
libc ++ proffers ios_base :: badbit
与所需的 ios_base :: iostate
一起作为解决方法使用
我们自己的 Howard Hinnant (谁也恰好是libc ++的代表谁无效链接的libc ++错误)建议在回答这个问题的重复(以及在libc ++错误)您使用解决方法:
is.exceptions(ios_base :: failbit | ios_base :: badbit);
I'm not sure about how to use std::istream::exception
according to the standard, to let std::istream::operator>>
throw an exception if it can't read the input into a variable, e.g. double.
The following code has different behavior with clang/libc++ and gcc/libstdc++:
#include <iostream>
#include <cassert>
int main () {
double foo,bar;
std::istream& is = std::cin;
is.exceptions(std::istream::failbit);
is >> foo; //throws exception as expected with gcc/libstdc++ with input "ASD"
std::cout << foo;
is >> bar;
std::cout << bar;
assert(is); //failed with clang/libc++ after input "ASD"
std::cout << foo << " " << bar << std::endl;
}
Is is.exceptions(std::istream::failbit);
right for the purpose to let operator>>
throw, according to the C++ standard?
First some background information (each of these is explained below under it's respective title if you would like further elaboration):
- The standard requires
istream
s to rethrow only whenios_base::badbit
is set inbasic_istream::exceptions
- libstdc++ does not comply with this requirement but libc++ does
- libc++ invalidates bugs requesting it's mirroring of libstdc++ behavior
- libc++ proffers
ios_base::badbit
bit-wise ored with the desiredios_base::iostate
as a workaround
Unfortunately this workaround has the side effect of also rethrowing whenever ios_base::badbit
is set independent of ios_base::failbit
: http://en.cppreference.com/w/cpp/io/ios_base/iostate#The_badbit
If you're looking for a throw to happen only when ios_base::failbit
is set and you need this to have the same behavior on libc++ and libstdc++ you'll have to check the ios_base::badbit
after each input operation occurring on the istream
. That'd need to look something like this:
if(is.rdstate() & ios_base::failbit != 0) throw ios_base::failure("basic_ios::clear");
As noted by cpplearner you can't even use basic_istream::fail
, you have to do a bit-wise test of the istream
's rdstate
return. But honestly that only adds a bit of complexity.
What could make this a monumental task is the extent to which the istream
is used. Wide usage of the istream
could be combated by helper functions, but use of istream_iterator
s or compound overloads of the extraction operator quickly make the manual inspection of this an unreasonable task.
If you find yourself there I would seriously consider the possibility of the is.exceptions(ios_base::failbit | ios_base::badbit)
workaround.
The standard requires istream
s to rethrow only when ios_base::badbit
is set in basic_istream::exceptions
Calling basic_istream::exceptions(istream::failbit)
will set a mask which can be retrieved by calling basic_istream::exceptions()
which according to 27.5.5.4 [iosstate.flags]/11 of the standard is:
A mask that determines what elements set in
rdstate()
cause exceptions to be thrown.
This is supported in 27.7.2.2.3 [istream::extractors]/15 for unformated insertion methods:
If it inserted no characters because it caught an exception thrown while extracting characters from
*this
andfailbit
is on inexceptions()
(27.5.5.4), then the caught exception is rethrown.
However for formatted input this is retrograded in 27.7.2.2.1 [istream.formatted.reqmts]/1; requiring a throw to occur only when a bit-wise and of the mask and ios_base::badbit
is non-zero:
If an exception is thrown during input then
ios::badbit
is turned on in*this
’s error state. If(exceptions()&badbit) != 0
then the exception is rethrown.
libstdc++ does not comply with this requirement but libc++ does
The ios_base::failbit
should be set on it's respective istream
on events such as:
The numeric, pointer, and boolean input overloads of
basic_istream::operator>>
(technically, the overloads ofnum_get::get
they call), if the input cannot be parsed as a valid value or if the value parsed does not fit in the destination type.
[Source]
If only the ios_base::failbit
is set on a basic_istream::exceptions
' mask and an event occurs, causing the ios_base::failbit
to be set, such as extracting an invalid number as described above:
- Under libstdc++ an exception is still rethrown, which does not conform to the standard
- Under libc++ no such exception is thrown, meaning the standard is upheld
libc++ invalidates bugs requesting it's mirroring of libstdc++ behavior
There is a now invalidated bug against libc++ for this very issue. Citing 27.7.2.1 [istream]/4
If one of these called functions throws an exception, then unless explicitly noted otherwise, the input function sets
badbit
in error state. Ifbadbit
is on inexceptions()
, the input function rethrows the exception without completing its actions, otherwise it does not throw anything and proceeds as if the called function had returned a failure indication.
libc++ proffers ios_base::badbit
bit-wise ored with the desired ios_base::iostate
as a workaround
Our own Howard Hinnant (who also happens to be libc++'s representative who invalidated the linked libc++ bug) suggests in answer to a duplicate of this question (as well as in the libc++ bug) that you use the workaround:
is.exceptions(ios_base::failbit | ios_base::badbit);
这篇关于std :: istream运算符异常重置/不抛出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!