How do you clear a stringstream variable?

Viewed 473604

I've tried several things already,

std::stringstream m;
m.empty();
m.clear();

both of which don't work.

9 Answers

For all the standard library types the member function empty() is a query, not a command, i.e. it means "are you empty?" not "please throw away your contents".

The clear() member function is inherited from ios and is used to clear the error state of the stream, e.g. if a file stream has the error state set to eofbit (end-of-file), then calling clear() will set the error state back to goodbit (no error).

For clearing the contents of a stringstream, using:

m.str("");

is correct, although using:

m.str(std::string());

is technically more efficient, because you avoid invoking the std::string constructor that takes const char*. But any compiler these days should be able to generate the same code in both cases - so I would just go with whatever is more readable.

There are many other answers that "work", but they often do unnecessary copies or reallocate memory.

  1. Swapping streams means that you need to discard one of them, wasting the memory allocation. Same goes for assigning a default-constructed stream,

  2. Assigning to the string in the string buffer (via stringstream::str or stringbuf::str) may lose the buffer already allocated by the string.

The canonical way to clear the string stream would be:

void clear(std::stringstream &stream)
{
   if (stream.rdbuf()) stream.rdbuf()->pubseekpos(0);
}

The canonical way to get the size of the data in the stream's buffer is:

std::size_t availSize() (const std::stringstream& stream)
{
   if (stream.rdbuf())
      return std::size_t(
         stream.rdbuf()->pubseekoff(0, std::ios_base::cur, std::ios_base::out));
   else
      return 0;
}

The canonical way to copy the data from the stream to some other preallocated buffer and then clear it would then be:

std::size_t readAndClear(std::stringstream &stream, void* outBuf, std::size_t outSize)
{
   auto const copySize = std::min(availSize(stream), outSize);
   if (!copySize) return 0; // takes care of null stream.rdbuf()

   stream.rdbuf()->sgetn(outBuf, copySize);
   stream.rdbuf()->pubseekpos(0); // clear the buffer

   return copySize;
}

I intend this to be a canonical answer. Language lawyers, feel free to pitch in.

Related