2

Pre-history: I'm trying to ensure that some function foo(std::stringstream&) consumes all data from the stream.

Answers to a previous question suggest that using stringstream::str() is the right way of getting content of a stringstream. I've also seen it being used to convert arbitrary type to string like this:

std::stringstream sstr;
sstr << 10;
assert(sstr.str() == std::string("10"));  // Conversion to std::string for clarity.

However, the notion of "content" is somewhat vague. For example, consider the following snippet:

#include <assert.h>
#include <sstream>
#include <iostream>

int main() {
  std::stringstream s;
  s << "10 20";
  int x;
  s >> x;
  std::cout << s.str() << "\n";
  return 0;
}

On Ideone (as well as on my system) this snippet prints 10 20, meaning that reading from stringstream does not modify what str() returns. So, my assumption is that that str() returns some internal buffer and it's up to stringstream (or, probably, its internal rdbuf, which is stringbuf by default) to handle "current position in that buffer". It's a known thing.

Looking at stringbuf::overflow() function (which re-allocates the buffer if there is not enough space), I can see that:

this may modify the pointers to both the input and output controlled sequences (up to all six of eback, gptr, egptr, pbase, pptr, epptr).

So, basically, there is no theoretical guarantee that writing to stringstream won't allocate a bigger buffer. Therefore, even using stringstream::str() for converting int to string is flawed: assert(sstr.str() == std::string("10")) from my first snippet can fail, because internal buffer is not guaranteed to be precisely of the necessary size.

Question is: what is the correct way of getting the "content" of stringstream, where "content" is defined as "all characters which could be consumed from the steream"?

Of course, one can read char-by-char, but I hope for a less verbose solution. I'm interested in the case where nothing is read from stringstream (my first snippet) as I never saw it fail.

Community
  • 1
  • 1
yeputons
  • 8,478
  • 34
  • 67

1 Answers1

0

You can use the tellg() function (inherited from std::basic_istream) to find the current input position. If it returns -1, there are no further characters to be consumed. Otherwise you can use s.str().substr(s.tellg()) to return the unconsumed characters in stringstream s.

GuyRT
  • 2,919
  • 13
  • 8
  • Sounds nice. Are you sure there is no need in something similar to `tellg` for "pointer to buffer's end" ([`egptr`](http://www.cplusplus.com/reference/streambuf/streambuf/egptr/), presumably?) – yeputons Apr 11 '17 at 20:27
  • 1
    Those functions in `streambuf` would be useful to do what you want without copying any data, but they're protected, so you can't access them. If you don't mind copying the data (as above), then the returned string terminates at the end of the buffer, so you don't need a "pointer to buffer's end" – GuyRT Apr 12 '17 at 11:03