我知道标题听起来很疯狂,但我现在正在亲身体验这一点,我想不出有什么理由会失败。
我正在使用getline()
阅读文件在阅读结束时,我打电话给tellg()。但是,此调用始终失败(返回值为-1)。
一个已知问题是tellg()不能与getline()一起使用,还是我做错了什么?
我使用的代码非常简单,基本上是
while(getline(file,line))
{
//tokenize and do other things
}
cout<<file.tellg()<<endl;
有问题的文件是常规磁盘上的一个简单的txt文件,我尝试使用和不使用CRLF的文件,它没有任何区别。
编辑:其他信息
gcc / g ++ 4.1.2,Linux(RHEL 5)
EDIT2: 根据这个帖子: http://www.cplusplus.com/forum/beginner/3599/#msg15540 由于某种gcc bug,不可能将getg与getline一起使用。实际情况如此吗? (你在网上看到的并不总是如此= P)
答案 0 :(得分:7)
tellg()
函数的工作原理是尝试构造一个sentry对象,然后在返回正确的值之前检查failbit
。如果设置了failbit
,则返回-1。可以找到详细信息here,或者,如果您更喜欢更官方的来源并且不介意干读,那么ISO C ++标准(27.6.1.3/36a-37
用于C ++ 03,27.7.2.3/39-40
用于C ++ 11)。
哨兵的构造首先检查error flags中的任何一个(如eofbit
),如果设置,则设置failbit
并返回。有关详细信息,请参阅here(C ++ 03 27.6.1.1.2
,C ++ 11 27.7.2.1.3
),
因此,设置文件结束标志后的tellg()
将失败。您在getline
返回false之前读取行的事实意味着正在设置流的eofbit
,因此您已到达文件的末尾。
您可以使用以下程序查看行为:
#include <iostream>
#include <iomanip>
int main (void) {
std::string line;
while (std::getline (std::cin, line)) {
if (line.length() > 20)
line = line.substr(0,17) + "...";
std::cout << "tellg() returned "
<< std::setw(5) << std::cin.tellg()
<< " after " << line << "\n";
}
//std::cin.clear();
std::cout << "tellg() returns: "
<< std::cin.tellg() << '\n';
return 0;
}
当你运行它并提供文件本身作为输入时,你会看到:
tellg() returned 20 after #include <iostream>
tellg() returned 39 after #include <iomanip>
tellg() returned 40 after
tellg() returned 58 after int main (void) {
tellg() returned 80 after std::string l...
tellg() returned 124 after while (std::g...
tellg() returned 156 after if (line....
tellg() returned 202 after line ...
tellg() returned 243 after std::cout...
tellg() returned 291 after << st...
tellg() returned 333 after << " ...
tellg() returned 339 after }
tellg() returned 363 after //std::cin.cl...
tellg() returned 400 after std::cout << ...
tellg() returned 437 after << std::c...
tellg() returned 451 after return 0;
tellg() returned 453 after }
tellg() returned 454 after
tellg() returns: -1
如果取消注释该代码中清除错误状态变量的行,它将起作用:
tellg() returned 20 after #include <iostream>
tellg() returned 39 after #include <iomanip>
tellg() returned 40 after
tellg() returned 58 after int main (void) {
tellg() returned 80 after std::string l...
tellg() returned 124 after while (std::g...
tellg() returned 156 after if (line....
tellg() returned 202 after line ...
tellg() returned 243 after std::cout...
tellg() returned 291 after << st...
tellg() returned 333 after << " ...
tellg() returned 339 after }
tellg() returned 361 after std::cin.clea...
tellg() returned 398 after std::cout << ...
tellg() returned 435 after << std::c...
tellg() returned 449 after return 0;
tellg() returned 451 after }
tellg() returned 452 after
tellg() returns: 452
而且,顺便说一句,看起来你所指的bug可能是this one(因为你链接的帖子遗憾地遗漏了任何细节,所以有点不清楚 - 如果海报打扰支持他断言这是一个已知的错误,例如链接到它。)
如果是这种情况,那么你应该注意的第一个事情就是它已经修复了十多年,所以,除非你使用绝对的古代 {{ 1}},现在不会成为一个问题。
答案 1 :(得分:0)
std::istream::tellg
不会告诉您任何内容。根据其规格,
返回:构建sentry对象后,如果
fail() != false
,则返回pos_type(-1)
以指示失败。否则,返回rdbuf()->pubseekoff(0, cur, in)
。
参考std::istream::sentry
,如果已设置fail
,则设置eof
。
但fail
和eof
已由clear
函数清除,这就是您需要做的所有事情。
while(getline(file,line))
{
//tokenize and do other things
}
file.clear(); // reset error state
cout<<file.tellg()<<endl;
即使您不打扰pubseekoff
,clear
功能仍然有效,所以这也有效:
cout<< static_cast< std::streamoff >( file.rdbuf()->pubseekoff(0, std::ios::cur, std::ios::in) )
<<endl;