C++ istream 运算符>>坏数据处理 [英] C++ istream operator>> bad-data handling
问题描述
每次我在 SO 上问一个问题,结果都是一些非常愚蠢的错误(如果你不相信我,请查看我的历史),所以如果可以的话,请耐心等待.
感觉我的问题应该很受欢迎,但我找不到任何关于它的东西,而且我已经没有想法可以尝试了.
总之,事不宜迟:
<小时>我正在尝试重载输入 operator>>
.它应该一次从文件中读取一个整数,跳过无效数据,例如 char
s、float
s 等.
当然,我正在检查 if(in >> inNum)
到 get() 下一个令牌 和 检查是否成功 get().
如果成功,那就没什么好说的了.
但是,如果它失败了,我假设发生了两件事之一:
- 它偶然发现了一个非整数
- 达到了eof
这是我尝试处理它的方法:
istream&运营商>>(istream& in, SortSetArray& setB) {bool eof = false;int inNum = -1;而(!eof){if(in >> inNum) {cout<<调试成功:inNum ="<<<输入数<<结束;setB.insert(inNum);}别的 {//检查 eof,使用 peek()//1. 清除所有标志,因为 peek() 返回 eof 不管什么//标志被提升,即使它不是 `eof`in.clear();cout<<调试失败:inNum ="<<输入数<<结束;//2. 然后用 peek() 检查 eofeof = (in.peek() == std::char_traits::eof());}}返回;}
文件包含[1 2 3 4 a 5 6 7],程序自然进入无限循环.好吧,很容易猜到,peek() 不消耗字符 'a',也许 in >>inNum
也未能以某种方式消耗它.没什么大不了的,我会尝试一些有用的东西.
这几乎就是我过去 2 小时去过的地方.我试过 istream::ignore()、istream::get()、ios::rdstate 来检查 eof、double
和 string
而不是 char
在文件中,以防 char
被数字读取.
没有任何效果,我很绝望.
奇怪的是,上述方法适用于以前的程序,在该程序中,我必须读取以下格式的三元组数据条目:string
int
int
唯一的区别是我为那个使用了 ifstream
对象,而为这个使用了 istream
对象.
额外问题:出现打嗝时 inNum 的值为 0.我猜这是 istream::operator>> 所做的事情?
实现说明
<块引用>
- 尝试读取 int
- 如果成功;
- 将读取值插入到
setB
- 下一次迭代
- 其他;
- 清除错误标志
- 检查以确保我们还没有到达文件末尾
- 还有更多数据?下一次迭代.
以上是你的函数的逻辑描述,但还缺少一些东西......
如果我们尝试读取值但失败,std::istream
会通过设置适当的错误标志来处理这些情况,但不会丢弃任何数据.
您的实现的问题在于,在尝试读取无效数据时,您只会尝试再次读取相同的无效数据......一遍又一遍,inf.
<小时>解决方案
清除错误标志后,您可以使用std::istream::ignore
丢弃流中的任何数据.
该函数的 1st 参数是要忽略的潜在 char
的最大数量,2nd 是如果你点击这个 char,不要再忽略*.
让我们忽略最大字符数,或者直到我们点击' '
(空格):
#include //std::numeric_limitsin.ignore (std::numeric_limits::max(), ' ');
Every time I ask a question here on SO, it turns out to be some very dumb mistake (check my history if you don't believe me), so bear with me if you can here.
It feels like my question should be very popular, but I couldn't find anything about it and I've run out of ideas to try.
Anyway, without further ado:
I'm trying to overload the input operator>>
. It's supposed to read one integer at a time from a file, skipping invalid data such as char
s, float
s, etc.
Naturally, I'm checking if(in >> inNum)
to both get() the next token and check for successful get().
If successful, not much to say there.
If it fails, however, I assume that one of two things happened:
- It stumbled upon a non-integer
- It reached the eof
Here's how I tried to deal with it:
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;
}
The file contains [1 2 3 4 a 5 6 7], and the program naturally goes into infinite loop.
Okay, easy guess, peek() doesn't consume the char 'a', and maybe in >> inNum
also failed to consume it somehow. No biggie, I'll just try something that does.
And that's pretty much where I've been for the last 2 hours. I tried istream::ignore(), istream::get(), ios::rdstate to check eof, double
and string
instead of char
in the file, just in case char
is read numerically.
Nothing works and I'm desperate.
Weirdly enough, the approach above worked for a previous program where I had to read a triplet of data entries on a line of the format: string
int
int
The only difference is I used an ifstream
object for that one, and an istream
object for this one.
Bonus Question: inNum has the value of 0 when the hiccup occurs. I'm guessing it's something that istream::operator>> does?
Implementation description
- try to read an int
- if successful;
- insert the read value to
setB
- next iteration
- else;
- clear error flags
- check so that we haven't reached the end of the file
- still more data? next iteration.
The above is the logic description of your function, but there's something missing...
In case we try to read a value, but fail, std::istream
's handle these cases by setting the approriate error flags, but it will not discard any data.
The problem with your implementation is that upon trying to read invalid data, you will just try to read the same invalid data again.. over, and over, and over, inf.
Solution
After clearing the error flags you can use std::istream::ignore
to discard any data from the stream.
The function's 1st argument is the max number of potential char
s to ignore, and the 2nd is the "if you hit this char, don't ignore any more*.
Let's ignore the maximum amount of characters, or until we hit ' '
(space):
#include <limits> // std::numeric_limits
in.ignore (std::numeric_limits<std::streamsize>::max(), ' ');
这篇关于C++ istream 运算符>>坏数据处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!