繁体   English   中英

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

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

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”:

Ex A 结果:Hello:CN Test, OU XYZ, O ABC

Ex B 结果:Hello:CN Test, OU XYZ, O

参考: CppReference.com,“iostate”

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

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

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

CppReference 状态,

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

你在这里遇到了一个例外。 .operator!()检查failbit而不是eofbit —— "ABC"getline()确实设置了eofbit (当到达流的 EOF 时),但不failbit (因为最后一个操作仍然成功)。 这使得.eof()结束循环(不打印"ABC" ),而.operator!()将再做一次迭代(打印"ABC" ),尝试另一个失败的getline() (因为没有什么可以做的了)读取),设置failbit ,并结束循环。

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


(*):请注意,还有更多测试。 唯一对称的是.fail().operator!() (测试相同的东西),以及它们对称的相反.operator bool() 其他的—— .good( .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. 现在在第二轮test中, getline成功( !!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 被称为在上下文中转换为 bool 并且当且仅当声明 bool t(e); 对于一些发明的临时变量 t (11.6) 是良构的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM