为什么字符串流>>失败时更改目标的值?

Why does stringstream >> change value of target on failure?

本文关键字:gt 目标 失败 字符串 为什么      更新时间:2023-10-16

摘自Stroustrup的TC++PL,第三版,第21.3.3节:

如果我们试图读取变量v,但操作失败,v的值应该保持不变(如果v是istream或ostream成员函数处理的类型之一,则它保持不变)。

下面的示例似乎与上面的引用相矛盾。根据上面的引用,我原本希望v的值保持不变,但它变成了零。对这种明显矛盾的行为有什么解释?

#include <iostream>
#include <sstream>
int main( )
{
std::stringstream  ss;
ss  << "The quick brown fox.";
int  v = 123;
std::cout << "Before: " << v << "n";
if( ss >> v )
{
std::cout << "Strange -- was successful at reading a word into an int!n";
}
std::cout << "After: " << v << "n";
if( ss.rdstate() & std::stringstream::eofbit  ) std::cout << "state: eofbitn";
if( ss.rdstate() & std::stringstream::failbit ) std::cout << "state: failbitn";
if( ss.rdstate() & std::stringstream::badbit  ) std::cout << "state: badbitn";
return 1;
}

我使用x86_64-w64-mingw32-g++.exe(ruenvb-4.7.2-release)4.7.2得到的输出是:

Before: 123
After: 0
state: failbit

谢谢。

来自此引用:

如果提取失败(例如,如果在需要数字的地方输入了一个字母),则值保持不变,并设置故障位(直到C++11)

如果提取失败,则将0写入值,并设置故障位。如果提取导致值太大或太小而无法放入值,则写入std::numeric_limits:max()或std::numeric_limits::min(),并设置故障位标志。(自C++11起)

编译器似乎是在C++11模式下编译的,这会改变行为。


输入运算符使用区域设置方面std::num_get,其get函数调用do_get。对于C++11,指定使用std::strtoll等类型的函数。在C++11之前,它显然使用了std::scanf风格的解析(根据引用,我无法访问C++03规范)来提取数字。行为的变化是由于解析输入时的这种变化。

运算符>>是一个格式化的输入运算符
因此,如何从流中读取输入取决于区域设置:

[isream.formatted.athmethyl]

与插入器一样,这些提取器取决于区域设置的num_get<>(22.4.2.1)对象来执行对输入流数据的解析。这些提取器表现为格式化的输入函数(如27.7.2.2.1所述)。在构造哨兵对象后,转换发生,就像由以下代码片段执行一样:

typedef num_get< charT,istreambuf_iterator<charT,traits> > numget;
iostate err = iostate::goodbit;
use_facet< numget >(loc).get(*this, 0, *this, err, val);
setstate(err);

正如我们在上面看到的,该值实际上是由流中嵌入的区域设置的numget方面设置的。

num_get虚拟函数[facet.num.get.virtuals]

第3阶段:

要存储的数值可以是以下值之一:

  • 零,如果转换函数无法转换整个字段。ios_base::failbit已分配给err
  • 如果字段表示的值太大而不能用val.iosbase::failbit表示,则表示最正的值
  • 对于无符号整数类型,如果字段表示的值太大而不能用值表示,则表示最负的值或零。ios_base::failbit被分配给err

第3阶段的定义在n2723->n2798 之间发生了巨大变化

在哪里可以找到当前的C或C++标准文档?

num_get虚拟函数[facet.num.get.virtuals]

第3阶段:第2阶段处理的结果可以是以下之一:

  • 在第2阶段中积累了一个字符序列,该序列被转换(根据scanf规则)为val类型的值。该值存储在val中,ios_base::goodbit存储在err中
  • 第2阶段中累积的字符序列会导致scanf报告输入失败。ios_base::failbit已分配给err