【问题标题】:istream behavior change in C++ upon failure失败时 C++ 中的 istream 行为变化
【发布时间】:2013-10-22 15:45:48
【问题描述】:

取自:cppreference

直到 C++11:

如果提取失败(例如,如果在需要数字的地方输入了字母),则值保持不变并设置失败位。

C++11 起:

如果提取失败,则将零写入 value 并设置 failbit。如果提取导致值太大或太小而无法容纳在值中,则写入 std::numeric_limits<T>::max()std::numeric_limits<T>::min() 并设置故障位标志。

由于这个变化,这意味着下面的sn-p:

int x = 1;
std::cin >> x;
return x;

如果数值转换失败,在C++11之前返回1,否则返回0

为什么标准委员会会引入如此微妙的突破性变化?或者更确切地说,在 C++11 之前,什么样的代码可能需要进行这种更改?

【问题讨论】:

  • 检查错误是您的责任。这既是pre-C++11C++11,也将出现在未来的版本中(很可能)。不检查而是依赖一些实现细节只是你的错。
  • @stefan 这太荒谬了。期望未修改的值依赖于实现细节,但检查故障位不?怎么回事?为什么我们还有接口规范和文档?你能解释一下为什么在“如果提取失败(例如,如果在需要数字的地方输入了一个字母),值保持不变并设置了失败位。” “值未修改”部分是实现细节,但“故障位已设置”部分不是吗?您不能选择性地挑选记录的行为并将其称为实现细节。
  • @stefan 不。这绝对不是实现细节。这是operator>>指定行为。它写在规范中。 operator>> 的指定行为的其他哪些部分您会选择性地忽略?
  • @stefan 我的意思是:如果您希望它在错误时返回 1,那么代码就可以了。嗯,是。规范以不兼容的方式更改并不是编写代码的人的错。
  • 另请参阅this answer 看起来,无论如何我们都不能真正依赖这种行为,所以在实践中这并没有太大的损失。

标签: c++ c++11


【解决方案1】:

看起来像最初指定的那样,operator>>s 在某些情况下被破坏(即严格来说不存在)。 这就是“修复”。

在 2011 年初的草案中,该标准在这方面与 2003 年基本相同。但是,在 Matt Austern(1998 年!)打开的库缺陷报告中,num_get<>::get() 不存在shortint。 于是改用long的版本,并检查读取数是否在正确的范围内。

缺陷报告为here

(并没有真正解释为什么他们认为自己不能保持最初的预期行为,但这就是标准的这一部分被更改的原因。)

【讨论】:

  • 这不包括这个问题所涉及的 num_get::get 阶段 3 的变化。
  • 我认为更好的链接是同一文档中的第 23 期
  • @Cubbi: 就是这个:)
【解决方案2】:

在非const 参考输入x 中存储零,然后在出错的情况下返回原始值,这更像是 C++ 的处理方式。

为了在出现错误情况时保留原始值,库必须使用临时值。它不能简单地使用x 提供的空间而不将原始值存储在某处。然后,一旦知道错误条件,它可能还必须在某个时候复制到x。如果出现错误或读取输入,您将如何获得原始值。所以每个人都付出代价,不管他们是否想要这种行为。

所以在出错的情况下返回原始值根本不是 C++。如果您希望这种行为只需自己付费 - 创建一个临时并将其非 const 引用传递给 operator>>,类似于:

int x = 1;
int temp;
if (std::cin >> temp) 
    x = temp;
return x;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多