【问题标题】:Testing stream.good() or !stream.eof() reads last line twice [duplicate]测试 stream.good() 或 !stream.eof() 读取最后一行两次 [重复]
【发布时间】:2011-05-18 11:44:17
【问题描述】:

可能重复:
Why is iostream::eof inside a loop condition considered wrong?

我有以下代码:

ifstream f("x.txt");
string line;
while (f.good()) {
  getline(f, line);
  // Use line here.
}

但这会读取最后一行两次。为什么会发生这种情况,我该如何解决?

发生了非常相似的事情:

ifstream f("x.txt");
string line;
while (!f.eof()) {
  getline(f, line);
  // Use line here.
}

【问题讨论】:

  • 这是怎么复制的?另一个答案甚至没有提到使用 good() 函数作为测试进行循环。
  • @JerryJeremiah 尝试检查当前流状态(例如.good(),.eof(),.fail())以预测未来读取操作的成功(例如@987654327)是相同的一般问题@, >>)。这不起作用,因为流状态会告诉您先前的读取操作是否失败/到达输入的末尾;它不会告诉您有关未来读取尝试的任何信息。

标签: c++ iostream


【解决方案1】:

您非常非常少想检查 bad、eof 和 good。特别是对于 eof (因为 !stream.eof() 是一个常见错误),当前处于 EOF 的流并不一定意味着最后一个输入操作失败;反之,不在 EOF 并不意味着最后一次输入成功。

所有流状态函数——fail、bad、eof 和 good——告诉你流的当前状态,而不是预测未来操作的成功。在所需操作之后检查流本身(相当于反向失败检查):

if (getline(stream, line)) {
  use(line);
}
else {
  handle_error();
}

if (stream >> foo >> bar) {
  use(foo, bar);
}
else {
  handle_error();
}

if (!(stream >> foo)) {  // operator! is overloaded for streams
  throw SomeException();
}
use(foo);

读取和处理所有行:

for (std::string line; getline(stream, line);) {
  process(line);
}

需要指出的是,good() 命名错误,并不等同于测试流本身(上面的例子就是这样做的)。

【讨论】:

  • 关于检查 eof 的部分是正确的,但是检查流本身的建议有点不对劲。 good() 表示未设置任何 eofbit、badbit 或 failbit。 fail() 表示设置了 badbit 或 failbit。检查流(使用 void* 转换或运算符!)与调用 fail() 成员函数完全相同。
  • @KeithB:您可能会注意到我将失败排除在“应该很少检查”组之外。失败的流很重要,检查流本身几乎总是比等效的 fail() 更方便。比较 getline(stream, line) 和 !getline(stream, line).fail()。
【解决方案2】:

随便用

ifstream f("x.txt");
while (getline(f, line)) {
    // whatever
}

这是编写这样一个循环的惯用方式。我无法重现该错误(在 Linux 机器上)。

【讨论】:

  • 我才刚刚意识到为什么会这样:最后一次成功调用 getline() 可能设置 eof,如果最后一行没有最后有一个换行符。 fail 位仅在对 getline() 的调用不成功时设置。所以我们不想想在eof处结束循环,但我们确实想在fail处结束循环。
  • 还有一件事.. 我一直在做while(f.peek() != EOF) { ... }。我认为这是正确的?但我以后会用你的答案。
【解决方案3】:

它没有读取最后一行两次,但由于它在到达 eof 时未能读取,因此您的字符串行具有之前的值。

那是因为 f 在读取 EOF 时不再是“好”,而不是在即将读取它时。

【讨论】:

    猜你喜欢
    • 2014-12-21
    • 1970-01-01
    • 2018-01-08
    • 2021-12-05
    • 1970-01-01
    • 1970-01-01
    • 2020-12-27
    • 2013-08-17
    • 1970-01-01
    相关资源
    最近更新 更多