【问题标题】:C++ istream operator>> bad-data handlingC++ istream 运算符>>坏数据处理
【发布时间】:2014-01-20 03:29:03
【问题描述】:

每次我在 SO 上提出问题时,结果都是一些非常愚蠢的错误(如果你不相信我,请查看我的历史记录),所以如果可以的话,请耐心等待。

感觉我的问题应该很受欢迎,但我找不到任何关于它的信息,而且我已经没有想法可以尝试了。

不管怎样,事不宜迟:


我正在尝试使输入 operator>> 过载。它应该从文件中一次读取一个整数跳过无效数据,例如chars、floats 等。

当然,我正在检查if(in >> inNum) 以同时get() 下一个令牌检查成功的get()
如果成功了,这里就不多说了。
但是,如果它失败了,我假设发生了以下两件事之一:

  1. 它偶然发现了一个非整数
  2. 它到达了eof

这是我尝试处理它的方法:

istream& operator>> (istream& in, SortSetArray& setB) {
    bool eof = false;
    int inNum = -1;
    while(!eof) {
        if(in >> inNum) {
            cout << "DEBUG SUCCESS: inNum = " << inNum << endl;
            setB.insert(inNum);
        }
        else {
            // check eof, using peek()
            // 1. clear all flags since peek() returns eof regardless of what
            //    flag is raised, even if it's not `eof`
            in.clear();
            cout << "DEBUG FAIL: inNum = " << inNum << endl;
            // 2. then check eof with peek()
            eof = (in.peek() == std::char_traits<char>::eof());
        }
    }
    return in;
}

文件包含[1 2 3 4 a 5 6 7],程序自然进入无限循环。 好吧,很容易猜到,peek() 不消耗字符'a',也许in &gt;&gt; inNum 也未能以某种方式消耗它。没什么大不了的,我会尝试一些可行的。

这就是我过去 2 个小时一直在的地方。我尝试使用 istream::ignore()、istream::get()、ios::rdstate 来检查文件中的 eof、doublestring 而不是 char,以防以数字方式读取 char

没有任何效果,我很绝望。

奇怪的是,上面的方法适用于之前的程序,我必须读取格式为一行的三组数据条目:stringintint
唯一的区别是我使用ifstream 对象作为那个对象,而istream 对象作为这个对象。

额外问题:当打嗝发生时,inNum 的值为 0。我猜这是 istream::operator>> 所做的事情?

【问题讨论】:

  • 使用in.clear(); 清除任何导致它的错误标志并重试。编辑:还添加cin.ignore(std::numeric_limits&lt;std::streamsize&gt;::max(), '\n'); 以删除卡在流中的字符
  • @Gasim 我不确定你的意思。这是我在 else{} 正文中做的第一件事。我还应该在哪里clear()
  • @Kafeaulait 您正确放置了clear() 调用。剩下要做的就是ignore() 冒犯的角色。如果文件格式是你所说的(一行空格分隔的字符),你所要做的就是is.ignore(); 忽略那个单个字符。确保这调用clear()之后进行。
  • @Gasim @0x499602D2 那行得通。虽然我不得不忽略直到找到' ' 而不是\n,因为我的数据都在一行上。很奇怪,当我在一小时前尝试时,它并没有忽略任何东西。这些标志可能以某种方式影响了ignore(),而clear() 成功了。谢谢大家。
  • 您说“我假设”,您为什么不使用调试器逐步完成?

标签: c++ operator-overloading


【解决方案1】:

实现说明

  1. 尝试读取 int
  2. 如果成功;
    1. 将读取值插入setB
    2. 下一次迭代
  3. 其他;
    1. 清除错误标志
    2. 检查以确保我们没有到达文件末尾
    3. 还有更多数据? 下一次迭代

上面是你的函数的逻辑描述,但是还少了点……

如果我们尝试读取一个值但失败了,std::istream 会通过设置适当的错误标志来处理这些情况,但它不会丢弃任何数据。

您的实现的问题在于,在尝试读取无效数据时,您只会尝试再次读取相同的无效数据.. 一遍又一遍,inf


解决方案

清除错误标志后,您可以使用std::istream::ignore 丢弃流中的任何数据。

函数的 1st 参数是可能忽略的chars 的最大数量,2nd 是“如果你点击这个 char em>,别再忽略了*。

让我们忽略最大字符数,或者直到我们点击' '(空格):

#include <limits> // std::numeric_limits

in.ignore (std::numeric_limits<std::streamsize>::max(), ' ');

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-23
    • 2011-03-19
    • 1970-01-01
    • 2020-02-10
    • 2016-05-28
    • 2021-08-07
    • 1970-01-01
    • 2021-12-16
    相关资源
    最近更新 更多