std :: istream运算符异常重置/不抛出

Sup*_*kus 3 c++ libstdc++ c++-standard-library libc++

我不确定如何std::istream::exception 根据标准使用,std::istream::operator>>如果无法将输入读入变量,则抛出异常,例如double.以下代码与clang/libc ++和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;

}
Run Code Online (Sandbox Code Playgroud)

根据C++标准,是否is.exceptions(std::istream::failbit);适合operator>>抛出目的?

Jon*_*Mee 7

首先是一些背景信息(如果您想进一步阐述,每个背景信息将在下面的相应标题下解释):

  • 该标准要求istreams ios_base::badbit设置时重新抛出basic_istream::exceptions
  • libstdc ++不符合此要求,但libc ++不符合此要求
  • libc ++使请求它镜像libstdc ++行为的bug无效
  • libc ++提供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");
Run Code Online (Sandbox Code Playgroud)

正如cpplearner所指出的那样,你甚至无法使用basic_istream::fail,你必须对它istreamrdstate回归进行逐步测试.但老实说,这只会增加一些复杂性.

什么能使这成为一项巨大的任务是使用的程度istream.istream可以通过辅助函数来对抗的广泛使用,但是使用istream_iterator提取操作符的s或复合过载会使得手动检查这是一项不合理的任务.

如果你发现自己在那里,我会认真考虑is.exceptions(ios_base::failbit | ios_base::badbit)解决方法的可能性.


该标准要求istreams ios_base::badbit设置时重新抛出basic_istream::exceptions

调用basic_istream::exceptions(istream::failbit)将设置一个掩码,可以通过调用basic_istream::exceptions()根据标准的27.5.5.4 [iosstate.flags]/11 调用来检索掩码:

一个掩码,用于确定要rdstate()引发异常的元素集.

对于未格式化的插入方法,27.7.2.2.3 [istream :: extractors]/15支持此操作:

如果未插入字符,因为它抓住了,同时从提取字符的抛出异常*this,并failbit是在exceptions()(27.5.5.4),然后将捕获的异常被重新抛出.

但是对于格式化输入,这将在27.7.2.2.1 [istream.formatted.reqmts]/1中进行逆行; 要求抛出仅在按位和掩码且ios_base::badbit非零时发生:

如果在输入期间抛出异常,则ios::badbit*this错误状态下打开.如果(exceptions()&badbit) != 0那么异常被重新抛出.


libstdc ++不符合此要求,但libc ++不符合此要求

ios_base::failbit应在其各自的设定istream上的事件,如:

数字,指针和布尔输入重载basic_istream::operator>>(技术上,num_get::get它们调用的重载),如果输入无法解析为有效值或者解析的值不适合目标类型.

[ 来源 ]

如果仅在'掩码ios_base::failbit上设置basic_istream::exceptions并且发生事件,则导致ios_base::failbit设置,例如如上所述提取无效数字:


libc ++使请求它镜像libstdc ++行为的bug无效

对于这个问题,针对libc ++存在一个现在无效的错误.引用27.7.2.1 [istream]/4

如果其中一个被调用的函数抛出异常,则除非另有明确说明,否则输入函数将设置badbit为错误状态.如果badbit处于打开状态exceptions(),输入函数将重新抛出异常而不完成其操作,否则它不会抛出任何内容并继续进行,就像被调用函数返回了失败指示一样.


libc ++提供ios_base::badbit了与所需的一对一ios_base::iostate的解决方法

我们自己的Howard Hinnant(也恰好是libc ++的代表,使链接的libc ++ bug无效)建议你回答这个问题的副本(以及libc ++ bug)你使用的解决方法:

is.exceptions(ios_base::failbit | ios_base::badbit);
Run Code Online (Sandbox Code Playgroud)