【问题标题】:Contents of the string after failed extraction from istream从 istream 中提取失败后的字符串内容
【发布时间】:2011-04-17 19:00:10
【问题描述】:

如果我这样做:

ifstream stream("somefilewhichopenssuccesfully.txt");
string token;
if( stream >> token )
    cout << token;
else
    cout << token;

第二种情况的输出是否保证为空字符串?我似乎在 cplusplus.com 上找不到这个问题的答案。

谢谢!

【问题讨论】:

    标签: c++ extraction istream


    【解决方案1】:

    第二种情况的输出是否保证为空字符串?

    答案是:不,因为它取决于,如下所述。

    因为else 块只有在尝试从流中读取失败时才会执行,并且在读取过程中随时可能发生。

    • 如果第一次尝试失败,则不会从流中提取字符,因此token 将是空的(原样)。

    • 如果在几次读取后失败,则token 不会为空。它将包含到目前为止从流中成功读取的字符。

    标准中的第 21.3.7.9 节说,

    从构造一个哨兵对象开始 k 好像 k 是由 typename 构造的 basic_istream::sentry k(是)。如果 bool(k) 为真,则调用 str.erase() 然后 提取 来自 is 的字符并将它们附加到 str 就像调用 str.append(1,c) 一样。 如果 is.width() 大于零, 最大字符数 n 附加的是 is.width();否则 n 是 str.max_size()。 字符是 提取并附加到任何 发生以下情况

    — n 个字符 被存储;

    ——文件结束发生在 输入序列;

    — isspace(c,is.getloc()) 对于 下一个可用的输入字符 c.

    在最后一个字符(如果有)之后是 提取,is.width(0) 被调用并且 哨兵对象 k 被销毁。

    如果函数没有提取到字符,它会调用 is.setstate(ios::failbit),这可能会抛出 ios_base::failure (27.4.4.3)。


    另请注意,标准中的第 §21.3.1/2 部分保证默认构造的字符串将为空。标准说它的大小为零,即为空。

    【讨论】:

    • @Nawaz:我的意思是保证istream 在不成功的情况下不会改变字符串。
    • @Nawaz:构造函数不相关,操作员无论如何都会清除字符串。关键是,如果几个字符已读入字符串,然后您通过读取操作设置了故障位,会发生什么 - 部分提取的字符串会发生什么。这似乎在标准中没有明确,它只在这种情况下提到了 eof。
    • @Nawaz:这仍然没有说明如果它提取 3 个字符并且 然后 得到除 EOF 之外的失败会发生什么。
    • @Erik:但不管它说什么,它清楚地表明token 在读取和追加时即使单次读取成功也不会为空。
    • @Nawaz:看起来是这样 - 所以对 OP 的回答是“否”。
    【解决方案2】:

    我删除了原来的答案,因为我想对此进行测试。这就是我所看到的,如果读取时出现错误(在此上下文中不计算 EOF),则修改原始字符串并且分支会看到修改后的版本。为了测试我做了以下,创建了一个 2Gb 文件(touch 然后truncate),上面的代码可以阅读。在代码运行时,删除了文件(这应该设置failbit - 我认为)。立即停止读取,但字符串被修改 - 它的大小更大。

    对我来说,这表明即使流操作失败,字符串也会被修改。

    【讨论】:

    • @Nawaz,抱歉您的评论断章取义,我删除了我原来的答案以正确测试。
    • 感谢您的努力,但这并不能保证这种行为无处不在。
    【解决方案3】:

    不,即使操作失败,字符串也会包含到目前为止提取的字符。

    标准说(§21.4.8.9):

    效果:表现为格式化输入函数 (27.7.2.2.1)。在构造sentry 对象后,如果哨兵转换为true,则调用str.erase(),然后从is 中提取字符并将它们附加到str,就像调用str.append(1,c) 一样。如果is.width()大于零,则追加的最大字符数为is.width();否则 n 为str.max_size()。字符被提取和附加,直到发生以下任何情况:
    — 存储 n 个字符;
    — 文件结束出现在输入序列上;
    isspace(c,is.getloc()) 对下一个可用的输入字符 c 为真。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-09-06
      • 1970-01-01
      • 2014-05-06
      • 2021-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-11
      相关资源
      最近更新 更多