std :: istream运算符异常重置/不抛出 [英] std::istream operator exception reset / not thrown

查看:237
本文介绍了std :: istream运算符异常重置/不抛出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不确定如何使用 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 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 ,例如如上所述提取无效数字:








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 istreams to rethrow only when ios_base::badbit is set in basic_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 desired ios_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_iterators 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 istreams 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 and failbit is on in exceptions() (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 of num_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:


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. If badbit is on in exceptions(), 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆