【问题标题】:Input stream iterators and exceptions输入流迭代器和异常
【发布时间】:2010-03-02 14:02:06
【问题描述】:

几天前我正在玩 istream 迭代器和异常处理,我遇到了这种好奇:

#include <iostream>
#include <fstream>
#include <iterator>
#include <algorithm>

using namespace std;

int main(int argc, char* argv[])
{
   if (argc < 2) {
      cout << argv[0] << " <file>" << endl;
      return -1;
   }

   try {
      ifstream ifs(argv[1]);
      ifs.exceptions(ios::failbit | ios::badbit);
      istream_iterator<string> iss(ifs), iss_end;
      copy(iss, iss_end, ostream_iterator<string>(cout, "\n"));
   }
   catch (const ios_base::failure& e) {
      cerr << e.what() << endl;
      return -2;
   }

   return 0;
}

为什么在读取输入文件的最后一个单词后总是引发故障位异常?

【问题讨论】:

  • 有人可以修复格式吗?
  • 当我在 C++ 中编程时,我从未使用迭代器读取文件,但在标准读取周期中,我有文件结束的特殊条件(即读取而不是 EOF)
  • @Roman:那你做错了。当出现读取错误时,仅测试 EOF 会导致无限循环,因为永远不会到达文件的末尾。最佳做法是始终测试 both 的 EOF 和失败。另一方面,OP 的代码使用异常,因此它是安全的。
  • @Konrad Rudolph:我只将 c++ 用于 ACM 竞赛,其中输入数据格式是严格预定义的。
  • @Roman:在大多数情况下,数据格式都是严格定义的。这不会改变你做错的事实。

标签: c++ exception iterator istream


【解决方案1】:

failbit 会在读取操作无法提取任何字符时设置,无论是因为它是否遇到 EOF。

stringstream ss ("foo");
string s;
int i;

ss >> i; // sets failbit because there is no number in the stream
ss.clear();
ss >> s; // sets eofbit because EOF is hit
ss.clear();
ss >> s; // sets eofbit and failbit because EOF is hit and nothing is extracted.

【讨论】:

    【解决方案2】:

    好问题。如果能够在该调用中捕获其他失败,但在遇​​到 eof 时让它继续正常运行,那就太好了。

    也就是说,我之前没有对流使用异常。我认为您可以进行复制并在之后检查流的状态以检测其他错误,例如:

    ifstream ifs(argv[1]);
    if (!ifs) {
        cerr << "Couldn't open " << argv[1] << '\n';
        return -1;
    }
    //ifs.exceptions(ios::failbit | ios::badbit);
    istream_iterator<std::string> iss(ifs), iss_end;
    copy(iss, iss_end, ostream_iterator<std::string>(cout, "\n"));
    if (!ifs.eof()) {
        cerr << "Failed to read the entire file.\n";
        return -2;
    }
    

    【讨论】:

    • @Roman:我无法在此程序中自己测试文件结束条件,因为我无法控制读取循环。必须对其进行测试的是算法“副本”。无论如何,istream_iterator 的默认构造函数会创建一个“过去的”迭代器(使用 STL 术语),在这种情况下是 EOF,以完成循环(“复制”的第二个参数)。
    • @AProgrammer:但这就是程序的诀窍(也是我提出问题的原因)。我没有在 ifs.exceptions(...) 中指定 ios::eofbit,所以“复制”应该正常到达文件末尾并且不会引发异常。我的意思是,如果我这样做的话,你说的就是正确的:ifs.exceptions(ios::failbit | ios::badbit | ios::eofbit)。
    • 您似乎将 cmets 放到了错误的帖子中 :) 但我认为 istream_iterator 失败时的结局,而不是 eof。此外,这些条件似乎无法单独进行可靠的测试。比如在coppro的回复中给“foo”加一个空格,你会发现eofbit和failbit是同时设置的。所以要么你不使用异常,要么你接受 EOF 是异常的......
    • 对不起,本斯叔叔!我认为这个文本框对于页面来说是“全局的”,直到我意识到每个回复都有自己的回复。我宁愿听从你的建议,不要使用例外。谢谢。好吧,也谢谢大家。
    【解决方案3】:

    通过读取直到失败(触发异常)然后检查失败原因来检测 EOF 条件。

    扩展:当使用 >> 读取值后,istream_iterator 变为无效,流运算符 void* 返回 NULL。但为此,运算符 >> 必须设置失败位,因此引发异常。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-11-14
      • 2020-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多