读取输入流失败时存储的值

3
样例代码:

示例代码:

#include <iostream>

int main()
{
    int x = 5;
    std::cin >> x;
    std::cout << x << '\n';
}

特定实现中,出现以下行为:
  • 输入:6;输出:6
  • 输入:a;输出:0
  • 输入:(文件结尾);输出:5
  • 输入:(空格后跟文件结尾);输出:5
因此,如果将文本转换为int的过程失败,则cin >> x会将x赋值为0;但如果失败是因为文件结束,则不会将其赋值为0
这种行为是否正确? 如果不正确,根据C++标准应该是什么正确的行为?
我想起之前在SO上讨论过所有情况都应该写0,因为从C++11开始,但使用搜索功能找不到任何东西;而且C++标准的iostreams部分相当深奥。
2个回答

3

是的,自C++11以来,这是正确的行为。

你看到的不同之处在于,当提取失败时会写入零,但如果EOF已经在流上设置,则根本不会尝试提取...因此什么也不会发生。


2
根据[istream.formatted.reqmts]的27.7.2.2.1第1段,格式化输入函数的第一步是构造一个std::istream::senty对象。进一步处理取决于这个对象是否转换为truefalse:如果sentry转换为false,则该值不会发生变化。
根据27.7.2.1.3 [istream::sentry]的第5和第7段,如果流的标志不是std::ios_base::goodbit,那么sentry将转换为false。也就是说,如果出现故障或达到EOF,则sentry将转换为false。因此,在跳过空白字符后达到EOF时,value保持为5,假设设置了std::ios_base::skipws。如果取消设置std::ios_base::skipws,并且至少有一个空格,则结果应为0
一旦解析实际完成,适用的逻辑在22.4.2.1.2 [facet.num.get.virtuals]的第3段中定义,第3阶段。关于受影响的值的关键部分如下:
“要存储的数字值可能是以下之一: - 如果转换函数无法转换整个字段,则为零。将ios_base::failbit分配给err。 - 如果该字段表示太大的正值,无法在val中表示,则为最大可表示值。将ios_base::failbit分配给err。 - 如果该字段表示太大的负值,无法在val中表示,则为最小可表示值或无符号整数类型的零。将ios_base::failbit分配给err。 - 否则为转换后的值。 结果的数字值存储在val中。”
因此,观察到的行为是正确的。
在C++11之前,在所有情况下都不会更改该值。认为区分错误并指示应表示哪个值是有必要的。对于如何更改行为的讨论持续了相当长的时间,并且实际上非常有争议。
如果在尝试转换之前达到EOF而未更改该值,则可能被认为是错误。我不记得在讨论更改时是否考虑过这种情况。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接