istream 读取失败时存储的值
Value stored when istream read fails
示例代码:
#include <iostream>
int main()
{
int x = 5;
std::cin >> x;
std::cout << x << '\n';
}
在 上发生以下行为:
- 输入:
6
;输出 6
- 输入:
a
;输出:0
- 输入:(文件结束);输出
5
- 输入:(空格后跟文件结尾);输出
5
因此,如果将文本转换为 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::goodbit
,sentry
将转换为 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,则值未更改可能被视为错误。我不记得在讨论更改时考虑过那个案例。
示例代码:
#include <iostream>
int main()
{
int x = 5;
std::cin >> x;
std::cout << x << '\n';
}
在
- 输入:
6
;输出6
- 输入:
a
;输出:0
- 输入:(文件结束);输出
5
- 输入:(空格后跟文件结尾);输出
5
因此,如果将文本转换为 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::goodbit
,sentry
将转换为 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 toerr
.— the most positive representable value, if the field represents a value too large positive to be represented in
val
.ios_base::failbit
is assigned toerr
.— 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 toerr
.— the converted value, otherwise.
The resultant numeric value is stored in
val
.
所以,观察到的行为是正确的。
对于 C++11 之前的版本,该值在所有情况下都保持不变。区分错误并用值指示应该表示哪个值被认为是可取的。关于如何改变行为的讨论持续了相当长的时间,实际上是有争议的。
如果在尝试转换之前达到 EOF,则值未更改可能被视为错误。我不记得在讨论更改时考虑过那个案例。