I know the title sounds crazy, but I'm experiencing this firsthand right now and I can't think of any reason why this is failing.
我知道这个名字听起来很疯狂,但我现在正亲身经历这一切,我想不出有什么理由让它失败。
I am reading through a file using getline()
我正在使用getline()读取文件
At the end of the reading, I call tellg(). However, this call always fails (return value of -1).
在阅读的最后,我叫tellg()。但是,这个调用总是失败(返回-1)。
Is it a known issue that tellg() doesn't work with getline() or am I doing something else wrong?
tellg()对getline()不起作用是一个已知的问题,还是我做错了别的事情?
The code I am using is very simple, basically
我使用的代码基本上非常简单
while(getline(file,line))
{
//tokenize and do other things
}
cout<<file.tellg()<<endl;
The file in question is a simple txt file on a regular disk, I tried a file with and without CRLF and it makes no difference.
问题中的文件是普通磁盘上的一个简单的txt文件,我尝试了一个带CRLF和不带CRLF的文件,它没有区别。
EDIT: Additional information
编辑:附加信息
gcc/g++ 4.1.2, Linux (RHEL 5)
Linux (RHEL 5)
EDIT2: According to this thread: http://www.cplusplus.com/forum/beginner/3599/#msg15540 It is impossible to use tellg with getline due to some sort of gcc bug. Is this actually the case? (what you read on the internet is not always true =P)
根据这个线程:http://www.cplusplus.com/forum/beginner/3599/#msg15540,由于某种gcc bug,无法在getline上使用tellg。真的是这样吗?(你在网上看到的不一定都是真的=P)
2 个解决方案
#1
6
The tellg()
function works by attempting to construct a sentry object and then checking for the failbit
before returning a proper value. If the failbit
is set, it returns -1. Details can be found here or, if you prefer a more official source and don't mind a dry read, the ISO C++ standard (27.6.1.3/36a-37
for C++03, 27.7.2.3/39-40
for C++11).
tellg()函数的工作方式是尝试构造一个哨兵对象,然后在返回适当的值之前检查故障位。如果设置了failbit,则返回-1。详细信息可以在这里找到,或者,如果您喜欢更正式的来源,而不介意干巴巴地阅读,ISO c++标准(c++ 03, 27.6.3 /36a-37, c++ 03, 27.7.3 /39-40)。
The construction of the sentry first checks any of the error flags (like eofbit
) and, if set, it sets the failbit
and returns. See here for detail (C++03 27.6.1.1.2
, C++11 27.7.2.1.3
),
哨兵的构造首先检查任何错误标志(如eofbit),如果设置,则设置故障比特并返回。详见此处(c++ 03 27.6.1.1.2, c++ 11 27.7.2.1.3),
Hence a tellg()
after the end of file flag has been set will fail. The fact that you're reading lines until getline
returns false means that the stream's eofbit
is being set, hence you've reached the end of the file.
因此,设置完文件标志后的tellg()将会失败。在getline返回false之前,您正在读取行,这意味着正在设置流的eofbit,因此您已经到达了文件的末尾。
You can see the behavior with this following program:
您可以通过以下程序看到行为:
#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;
}
When you run that and provide the file itself as input, you see:
当您运行它并将文件本身作为输入提供时,您将看到:
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
If you uncomment the line in that code which clears the error state variables, it will work:
如果您取消注释代码中清除错误状态变量的行,它将工作:
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
And, as an aside, it looks like the bug you're referring to may be this one (it's a little unclear since the post you linked to is sadly missing any detail - it would have been better had the poster bothered to support his assertion that it was a known bug by, for example, linking to it).
说句题外话,它看起来像你指的错误可能是这个(有点不清楚因为后你与令人遗憾错过任何细节,它将会更好的海报去支持他的说法,这是一个已知的缺陷,例如,链接到它)。
If that's the case, the first thing you should notice is that it was fixed more than a decade ago so, unless you're using an absolutely ancient gcc
, it's not going to be an issue now.
如果是这样的话,你首先要注意的是,它是十多年前修复的,所以,除非你使用的是一个绝对古老的gcc,否则它现在不会成为问题。
#2
0
std::istream::tellg
does not tell you anything if the stream's error flag is set. According to its spec,
如果设置了流的错误标志,tellg不会告诉您任何信息。
Returns: After constructing a sentry object, if
fail() != false
, returnspos_type(-1)
to indicate failure. Otherwise, returnsrdbuf()->pubseekoff(0, cur, in)
.返回:在构造一个哨兵对象之后,如果fail() != false,返回pos_type(-1)以指示失败。否则,返回rdbuf()->pubseekoff(0, cur, in)。
Referring to std::istream::sentry
, it sets fail
if eof
is already set.
引用std::istream: sentry,如果eof已经设置,则设置失败。
But fail
and eof
are cleared by the clear
function, which is all you need to do.
但是fail和eof是通过clear函数清除的,这就是您需要做的。
while(getline(file,line))
{
//tokenize and do other things
}
file.clear(); // reset error state
cout<<file.tellg()<<endl;
And the pubseekoff
function still works even if you don't bother with clear
, so this works too:
pubseekoff函数仍然可以工作即使你不需要清除,所以这个也可以:
cout<< static_cast< std::streamoff >( file.rdbuf()->pubseekoff(0, std::ios::cur, std::ios::in) )
<<endl;
#1
6
The tellg()
function works by attempting to construct a sentry object and then checking for the failbit
before returning a proper value. If the failbit
is set, it returns -1. Details can be found here or, if you prefer a more official source and don't mind a dry read, the ISO C++ standard (27.6.1.3/36a-37
for C++03, 27.7.2.3/39-40
for C++11).
tellg()函数的工作方式是尝试构造一个哨兵对象,然后在返回适当的值之前检查故障位。如果设置了failbit,则返回-1。详细信息可以在这里找到,或者,如果您喜欢更正式的来源,而不介意干巴巴地阅读,ISO c++标准(c++ 03, 27.6.3 /36a-37, c++ 03, 27.7.3 /39-40)。
The construction of the sentry first checks any of the error flags (like eofbit
) and, if set, it sets the failbit
and returns. See here for detail (C++03 27.6.1.1.2
, C++11 27.7.2.1.3
),
哨兵的构造首先检查任何错误标志(如eofbit),如果设置,则设置故障比特并返回。详见此处(c++ 03 27.6.1.1.2, c++ 11 27.7.2.1.3),
Hence a tellg()
after the end of file flag has been set will fail. The fact that you're reading lines until getline
returns false means that the stream's eofbit
is being set, hence you've reached the end of the file.
因此,设置完文件标志后的tellg()将会失败。在getline返回false之前,您正在读取行,这意味着正在设置流的eofbit,因此您已经到达了文件的末尾。
You can see the behavior with this following program:
您可以通过以下程序看到行为:
#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;
}
When you run that and provide the file itself as input, you see:
当您运行它并将文件本身作为输入提供时,您将看到:
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
If you uncomment the line in that code which clears the error state variables, it will work:
如果您取消注释代码中清除错误状态变量的行,它将工作:
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
And, as an aside, it looks like the bug you're referring to may be this one (it's a little unclear since the post you linked to is sadly missing any detail - it would have been better had the poster bothered to support his assertion that it was a known bug by, for example, linking to it).
说句题外话,它看起来像你指的错误可能是这个(有点不清楚因为后你与令人遗憾错过任何细节,它将会更好的海报去支持他的说法,这是一个已知的缺陷,例如,链接到它)。
If that's the case, the first thing you should notice is that it was fixed more than a decade ago so, unless you're using an absolutely ancient gcc
, it's not going to be an issue now.
如果是这样的话,你首先要注意的是,它是十多年前修复的,所以,除非你使用的是一个绝对古老的gcc,否则它现在不会成为问题。
#2
0
std::istream::tellg
does not tell you anything if the stream's error flag is set. According to its spec,
如果设置了流的错误标志,tellg不会告诉您任何信息。
Returns: After constructing a sentry object, if
fail() != false
, returnspos_type(-1)
to indicate failure. Otherwise, returnsrdbuf()->pubseekoff(0, cur, in)
.返回:在构造一个哨兵对象之后,如果fail() != false,返回pos_type(-1)以指示失败。否则,返回rdbuf()->pubseekoff(0, cur, in)。
Referring to std::istream::sentry
, it sets fail
if eof
is already set.
引用std::istream: sentry,如果eof已经设置,则设置失败。
But fail
and eof
are cleared by the clear
function, which is all you need to do.
但是fail和eof是通过clear函数清除的,这就是您需要做的。
while(getline(file,line))
{
//tokenize and do other things
}
file.clear(); // reset error state
cout<<file.tellg()<<endl;
And the pubseekoff
function still works even if you don't bother with clear
, so this works too:
pubseekoff函数仍然可以工作即使你不需要清除,所以这个也可以:
cout<< static_cast< std::streamoff >( file.rdbuf()->pubseekoff(0, std::ios::cur, std::ios::in) )
<<endl;