C ++ tellg () not working with getline ()?

I know the name sounds crazy, but I can feel it right now, and I can’t figure out why this is happening.

I am reading a file using getline ()

At the end of the reading, I call tellg (). However, this call always fails (return value -1).

Is tellg () known to not work with getline (), or am I doing something else wrong?

The code I use is very simple, basically

while(getline(file,line)) { //tokenize and do other things } cout<<file.tellg()<<endl; 

This file is a simple txt file on a regular disk, I tried the file with CRLF and without it. It does not matter.

EDIT: Additional Information

gcc / g ++ 4.1.2, Linux (RHEL 5)

EDIT2: According to this topic: http://www.cplusplus.com/forum/beginner/3599/#msg15540 Cannot use tellg with getline due to some gcc error. Is it really? (what you read on the Internet is not always true = P)

+4
source share
2 answers

The tellg() function works by trying to build a watchdog and then checking failbit before returning the correct value. If failbit set, it returns -1. Details can be found here or, if you prefer a more official source and do not mind dry reading, the ISO C ++ standard ( 27.6.1.3/36a-37 for C ++ 03, 27.7.2.3/39-40 for C ++ 11) .

Design time first checks for any error flags (eg, eofbit ), and, if installed, it sets failbit and returns. See here for more details (C ++ 03 27.6.1.1.2 , C ++ 11 27.7.2.1.3 ),

Therefore, a tellg() after the file flag is set will fail. The fact that you read the lines until getline returns false means that the eofbit stream eofbit installed, so you have reached the end of the file.

You can see the behavior of 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 this and provide the file as input, you will 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 a line in this code that 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, aside, it seems that the error you are talking about may be this (it’s a little unclear from the moment you are attached to it, any detail is sadly missing - it would be better if the poster bothered to support its statement that it was a known error, for example, related to it).

If so, the first thing you should notice is that it was fixed more than ten years ago, so if you are not using absolutely ancient gcc , now this will not be a problem.

+6
source

std::istream::tellg says nothing if the stream error flag is set. According to its specification,

Returns: after creating the sentinel object, if fail() != false , returns pos_type(-1) to indicate a failure. Otherwise returns rdbuf()->pubseekoff(0, cur, in) .

Referring to std::istream::sentry , it sets fail if eof already installed.

But fail and eof cleared by a clear , that all you need to do.

 while(getline(file,line)) { //tokenize and do other things } file.clear(); // reset error state cout<<file.tellg()<<endl; 

And the pubseekoff function works even if you are not worried about clear , so this works too:

 cout<< static_cast< std::streamoff >( file.rdbuf()->pubseekoff(0, std::ios::cur, std::ios::in) ) <<endl; 
0
source

Source: https://habr.com/ru/post/1488191/


All Articles