schnedan
schnedan

Reputation: 282

C++ stringstreams, why getline does not consume content of stream?

I found a odd behavior concerning stringstreams and getline [C++].

What am I doing?

In normal operation I stuff strings for logging into a stringstream, which I use as a simple self scaling buffer. Then on certain events I use getline to extract complete lines from the buffer-stream filter em for certain criteria and if they match I put such lines to one or more output streams for generating log output (on screen, to files, you name it...). In Case of termination of my programm - normal or abnormal, I want to grab what is left in the buffer (incomplete line[s]) an also put that to the output streams. For that I thought the normal str() method of stringstream will do the job.

unfortunately it turns out that getline seems to not consume the lines extracted, so str() replicates my complete log since start of program. Which

  1. produces unwanted output
  2. must result in an ever growing log-buffer (consuming all memory at a given point in time)

This samal demo shows the problem:

#include <iostream>
#include <sstream>

using namespace std;

int main(int argc, char **argv)
{
    stringstream ss;

  ss << "1\n1";
  ss << "22\n22";
  ss << "333\n333";
  ss << "4444\n4444";
  ss << "55555\n55555";
  ss << "666666\n666666";
  ss << "7777777\n7777777";

  for (std::string line; std::getline(ss, line); ) {
    cout << line << ",";
  }
  cout << "\n";

  cout << ss.str() << "\n";

    return 0;
}

And the resulting output is:

1,122,22333,3334444,444455555,55555666666,6666667777777,7777777,
1
122
22333
3334444
444455555
55555666666
6666667777777
7777777
Hit any key to continue...

So the first Line of output is what getline extracted, and afterwards std() still returns the complete string from the stream.

Also I am a bit puzzled, why getline also extracts the last "7777777" as it is not followed by a linebreak.

So my question is, how to extract lines, and only lines followed by a '\n' from a stringstream, extract in the sense of: what is read from the stringstream is no longer in the stringstream and also leaving incomplete lines untouched inside the stream - for later processing.

PS: I can not use boost, its embedded stuff and boost is way to much here.

Upvotes: 1

Views: 3086

Answers (1)

M.M
M.M

Reputation: 141648

Firstly getline can be terminated by end-of-file condition, not just the line terminator. So this explains your last line.

Regarding the first question, stringstreams are like a file stored in memory. Reading from it advances the file pointer without deleting the file. You can rewind back to the start at any time.

There isn't a command to delete from memory just the bits you have read so far; if you want that functionality then stringstream is not the right class to use. You may have to roll your own FIFO structure , e.g. use queue<string> to back a streaming input interface.

Or perhaps you could clear the stringstream buffer once you finished extracting everything from it (this seems like normal usage for a log buffer?)

Upvotes: 1

Related Questions