istream 读取失败时存储的值

Value stored when istream read fails

示例代码:

#include <iostream>

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

上发生以下行为:

因此,如果将文本转换为 int 失败,cin >> x 会将 0 分配给 x;但如果失败是由于文件结束造成的,则不会分配 0

这是正确的行为吗?如果不是,根据 C++ 标准,正确的行为是什么?

我记得以前在 SO 上讨论过,从 C++11 开始,所有情况都应该写成 0,但我无法使用搜索功能找到任何东西; C++ 标准的 iostreams 部分非常繁重。

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

  • istream behavior change in C++ upon failure

您所看到的不同之处在于写了一个零 "when extraction fails",但如果流上已经设置了 EOF,则甚至不会尝试提取……所以什么也没有发生。

根据 27.7.2.2.1 [istream.formatted.reqmts] 第 1 段,格式化输入函数的第一件事是构造一个 std::istream::senty 对象。进一步处理取决于此对象是转换为 true 还是 false:如果 sentry 转换为 false.

,则值不会发生任何变化

根据 27.7.2.1.3 [istream::sentry] 第 5 和第 7 段,如果流的标志不是 std::ios_base::goodbitsentry 将转换为 false。也就是说,如果发生故障或达到 EOF,sentry 将转换为 false。因此,假设设置了 std::ios_base::skipws,在跳过 whitespace 后到达 EOF 时,value 停留在 5。如果至少有一个 space.

,取消设置 std::ios_base::skipws 应该导致值变为 0

一旦解析实际完成,应用逻辑在 22.4.2.1.2 [facet.num.get.virtuals] 第 3 段,第 3 阶段中定义。影响值的关键部分是

...

The numeric value to be stored can be one of:

— zero, if the conversion function fails to convert the entire field. ios_base::failbit is assigned to err.

— the most positive representable value, if the field represents a value too large positive to be represented in val. ios_base::failbit is assigned to err.

— the most negative representable value or zero for an unsigned integer type, if the field represents a value too large negative to be represented in val. ios_base::failbit is assigned to err.

— the converted value, otherwise.

The resultant numeric value is stored in val.

所以,观察到的行为是正确的。

对于 C++11 之前的版本,该值在所有情况下都保持不变。区分错误并用值指示应该表示哪个值被认为是可取的。关于如何改变行为的讨论持续了相当长的时间,实际上是有争议的。

如果在尝试转换之前达到 EOF,则值未更改可能被视为错误。我不记得在讨论更改时考虑过那个案例。