C++ 使用std::istream::peek()是否总是安全的?

C++ 使用std::istream::peek()是否总是安全的?,c++,istream,C++,Istream,我通常教我的学生处理文件输入的安全方法是: while (true) { // Try to read if (/* failure check */) { break; } // Use what you read } 这使我和许多人从古典主义和大多数错误中解脱出来: while (!is.eof()) { // Try to read // Use what you read } 但人们确实喜欢这种形式的循环,因此在学生代码

我通常教我的学生处理文件输入的安全方法是:

while (true) {
    // Try to read
    if (/* failure check */) {
        break;
    }
    // Use what you read
}
这使我和许多人从古典主义和大多数错误中解脱出来:

while (!is.eof()) {
    // Try to read
    // Use what you read
}
但人们确实喜欢这种形式的循环,因此在学生代码中看到这种情况已经很常见:

while (is.peek()!=EOF) { // <-- I know this is not C++ style, but this is how it is usually written
    // Try to read
    // Use what you read
}
while(is.peek()!=EOF){/
is.peek()!=EOF
告诉您输入流中是否还有字符,但它不会告诉您下次读取是否成功:

while (is.peek()!=EOF) {
    int a;
    is >> a;
    // Still need to test `is` to verify that the read succeeded
}
是>>一个
可能会由于多种原因而失败,例如,输入可能实际上不是一个数字

因此,如果你可以这样做的话,这是没有意义的

int a;
while (is >> a) { // reads until failure of any kind
    // use `a`
}
或者,也许更好:

for (int a; is >> a;) { // reads until failure of any kind
    // use `a`
}
或者您的第一个示例,在这种情况下,循环中的
是.peek()!=EOF
,将变得多余


这是假设您希望循环在每次失败时退出,遵循您的第一个代码示例,而不仅仅是在文件末尾。

for(int a;is>>a;)
好的,这是很清楚的。因此,如果我假设读取失败的唯一原因是到达文件末尾(一个非常强烈和慷慨的假设),这个想法是正确的,对吗?即使以后有人玩
std::istream::unget()
?@CostantinoGrana你确定这是一个很好的假设吗?例如,如果输入的末尾有空格,那么
peek()也可以
将不会返回EOF,尽管所有格式化读取都将失败。我不确定您对
unget()
的想法,但我认为
unget()
可能会更改
peek()
将EOF返回为不返回EOF。@胡桃木不,我确信这不是一个好的假设。但是在考试期间,你有时会向学生保证文件格式正确,因此他们不需要做所有检查。大多数时候,我们处理的是二进制格式,这让你完全不用担心空白(因为数据都是有意义的。)我想到了
unget()
的东西,因为我曾经观察到(我相信是在Windows上),通过查看4096缓冲区限制,取消设置上一个字节(上一个缓冲区的最后一个字节)失败。但我可能错了。这就是我的疑问:我遗漏了一些已知的东西。@CostantinoGrana您可能希望在您的问题中澄清这些问题,以便其他人可以添加答案。老实说,我认为我对streams库的内部结构了解不够,无法回答这个问题。您可能想看看第4个条件只是有点le更好。通常使用read函数本身控制读取总是更好的,例如
while(std::cin>>var){/*handle var*/}
while(getline(fp,str)){/*handle string*/}
等等。。。