在getline上检查eof()有什么区别,即while(!getline().eof())和简单地检查while(ge

What is difference in checking eof() on getline i.e. while(!getline().eof()) and checking simply while(getline())

本文关键字:getline eof while 检查 ge 简单 什么 区别      更新时间:2023-10-16

while(getline()) 和 while(!getline().eof()) 有什么区别?

正在解析输入字符串。 我已经尝试了两种条件检查,我看到了结果的差异。

std::string testStr = "CN=Test, OU=XYZ, O=ABC";
std::stringstream inpStrStream(testStr);
std::string tempStr;
getline(inpStrStream, tempStr, '=');
std::cout<<"Hello:"<<tempStr<<std::endl;
//Let's call this as "Ex A"
while(getline(inpStrStream, tempStr, '='))
{
std::cout<<tempStr<<std::endl;
}
(OR)
//Let's call this as "Ex B"
while(!getline(inpStrStream, tempStr, '=').eof())
{
std::cout<<tempStr<<std::endl;
}

我期望两者的结果相同,但"Ex A"和"Ex B"的结果不同。我在"Ex B"的输出中看不到字符串"ABC":

例如 A 结果: 您好:中国 测试, OU XYZ, O 美国广播公司

例 B 结果: 您好:中国 测试, OU XYZ, O

Ref.: CppReference.com, "iostate">

getline()返回它正在操作的流的引用,即inpStrStream.

inpStrStream.operator bool()(或while ( inpStrStream )/while ( getline( inpStrStream, tempStr, '=' ) ))将检查是否设置了流的failbitbadbit

! inpStrStream.eof()将检查是否设置了流eofbit。(*)

Cpp首选项声明,

。在几乎所有情况下,如果设置了eofbit,则也会设置failbit

您在此处遇到了其中一个例外。.operator!()检查failbit而不是eofbit- 蚂蚁"ABC"getline()确实设置了eofbit(当达到流的EOF时),但不failbit(因为最后一个操作仍然成功)。这使得.eof()结束循环(不打印"ABC"),而.operator!()将再做一次迭代(打印"ABC"),尝试另一个getline(),失败(因为没有更多要读取的内容),设置failbit,并结束循环。

所以。。。.eof()仅显式测试 EOF,即即使底层流发生了令人讨厌的事情,并且确实设置了其他两个标志之一,也会尝试继续。


(*):请注意,还有更多测试。唯一对称的是.fail().operator!()(它们测试相同的东西),它们的对称相反.operator bool()。其他的——.good().bad().eof()——分别检查不同的东西!

看看这个简单的测试代码:

#include <iostream>
#include <sstream>
#define LOG(x) std::cout << __LINE__ << ": " #x " = " << x << 'n'
void test(char termChar)
{
std::stringstream input;
input << "lets try this!";
std::string s;
std::getline(input, s, termChar);

LOG(!!input);
LOG(input.eof());
LOG(input.tellg());
char ch = '?';

input >> ch;
LOG(!!input);
LOG(input.eof());
LOG(input.tellg());
LOG(ch);
}
int main()
{
test('!');
std::cout << 'n';
test('#');

return 0;
}

其输出:https://godbolt.org/z/f55eTjWK1

14: !!input = 1
15: input.eof() = 0
16: input.tellg() = 14
20: !!input = 0
21: input.eof() = 1
22: input.tellg() = -1
23: ch = ?
14: !!input = 1
15: input.eof() = 1
16: input.tellg() = -1
20: !!input = 0
21: input.eof() = 1
22: input.tellg() = -1
23: ch = ?
  1. 请记住eof并不意味着您处于流的末尾,而是您尝试读取超出其大小的流。
  2. 现在在第二次运行中testgetline成功(!!input),但有人试图读取超出流大小的读取,因此eof返回true。现在,您与eof的循环可以拒绝对您来说重要的事情,因为eof设置为true但阅读是成功的。

std::stringstream继承定义运算符的类std::basic_ios

explicit operator bool() const;

1 返回: !fail()。

此运算符用于 while 语句的条件

while(getline(inpStrStream, tempStr, '=')) 

以上下文方式将调用std::getline返回的对象转换为 bool 类型。

从C++标准(C++ 17、7 标准转换)

4 某些语言结构要求转换表达式 到布尔值。在这样的上下文中出现的表达式 e 是 据说在上下文中转换为布尔值,并且格式良好,如果和 仅当声明布尔 t(e);格式良好,对于某些发明者 临时变量 T (11.6)。