105

How do I "reset" the state of a stringstream to what it was when I created it?

int firstValue = 1;
int secondValue = 2;

std::wstringstream ss;

ss << "Hello: " << firstValue;

std::wstring firstText(ss.str());

//print the value of firstText here


//How do I "reset" the stringstream here?
//I would like it behave as if I had created
// stringstream ss2 and used it below.


ss << "Bye: " << secondValue;

std::wstring secondText(ss.str());

//print the value of secondText here
user974967
  • 2,928
  • 10
  • 28
  • 45

3 Answers3

158

This is the way I usually do it:

ss.str("");
ss.clear(); // Clear state flags.
Darcy Rayner
  • 3,385
  • 1
  • 23
  • 15
  • 1
    Thanks; debugging someone else's C++ and needed this to sort out an access violation error they were getting due to not doing the .clear() method. Worked fine on an intel box but puked every time on an AMD machine. – Chris Townsend Oct 09 '12 at 15:19
  • 4
    Unfortunately `clear` doesn't reset io manipulators. Example failing test: std::stringstream ss; ss << "Hello" << std::setw(15) << "World" << std::setw(15); reset(ss); ss << "Hello World"; assert("Hello World" == buf.str()); // fails, picks up last std::setw – GameSalutes Feb 17 '18 at 20:48
15

I would do

std::wstringstream temp;
ss.swap(temp);

Edit: fixed the error reported by christianparpart and Nemo. Thanks.

PS: The above code creates a new stringstream object on the stack and swaps everything in ss with those in the new object.

Advantages:

  1. It guarantees ss will now be in a fresh-new state.
  2. The new object is created inline and on the stack, so that the compiler can easily optimize the code. At the end, it will be like resetting all ss internal data to initial state.

More:

  1. Compared to assignment operator: STL swap methods can be faster than assignment operator in the cases where the new object has an allocated buffer in the heap. In such a case, assignment operator has to allocate the buffer for the new object, then it MAY need to allocate another buffer for the old object, and then copy the data from the new object's buffer to the old object's new buffer. It is very easy to implement a fast swap, which just swaps pointers of the buffers for example.

  2. C++11. I have seen some implementation of move assignment operator that is slower than swap, although that can be fixed, but probably STL developer won't want to leave a moved object with a lot of data

  3. std::move() doesn't guarantee the moved object is emptied. return std::move(m_container); doesn't clear m_container. So you will have to do

    auto to_return(std::move(m_container)); m_container.clear(); return to_return;

Which can't be better than

auto to_return;
m_container.swap(to_return);
return to_return;

because the latter guarantees it won't copy buffers.

So I always prefer swap() as long as it fits.

Yong
  • 424
  • 4
  • 8
  • 2
    You should explain **why** you would do this. This code isn't terribly useful by itself. – Machavity Oct 05 '15 at 18:40
  • 1
    While this answer may be correct, please add some explanation. Imparting the underlying logic is more important than just giving the code, because it helps the OP and other readers fix this and similar issues themselves. – CodeMouse92 Oct 05 '15 at 21:38
  • I like the solution. It's very short, and the same template works for practically all std datatypes. – martinus Jun 15 '16 at 11:44
  • 1
    This answer is not quite correct as you may not bind to a temporary, that is, you create a temporary variable to swap the newly (temporarily) created empty string stream with the existing "ss" one. Not allowed. – christianparpart Aug 07 '16 at 22:06
  • Doesn't this incur all the overhead of constructing a locale, which resetting the stringstream is supposed to avoid? – caps Nov 16 '16 at 23:59
  • @trapni the local variable is not a temporary variable. – Yong Apr 17 '17 at 19:27
  • @caps that's true. – Yong Apr 17 '17 at 19:27
  • Note that stringstream::swap() is not available prior to C++11. – Nemo May 22 '17 at 20:56
  • Why I get `error: invalid initialization of non-const reference of type ‘std::__cxx11::basic_stringstream&’ from an rvalue of type ‘std::wstringstream {aka std::__cxx11::basic_stringstream}’` (using GCC 5.4.0 with std=c++11) – Patrizio Bertoni Aug 22 '17 at 08:31
  • swap will reset previous std::fixed etc. – AJ_Nur Apr 27 '21 at 04:34
  • a one liner: `std::stringstream{}.swap(ss);` – Dvir Yitzchaki Jul 23 '21 at 14:32
  • In current C++ i just use `ss = {};` to reset everything – Andreas H. Jul 19 '22 at 06:57
6

Building on answer above, we also need to reset any formatting. In all we are resetting the buffer contents, the stream state flags, and any formatting to their defaults when a new std::stringstream instance is constructed.

void reset(std::stringstream& stream)
{
    const static std::stringstream initial;
    
    stream.str(std::string());
    stream.clear();
    stream.copyfmt(initial);
}
vickers
  • 5
  • 3
GameSalutes
  • 1,762
  • 2
  • 18
  • 24
  • The call to `stream.cpyfmt(initial)` will reset the locale of `stream` to match the locale of `initial`, according to [cppreference](https://en.cppreference.com/w/cpp/io/basic_ios/copyfmt). So imbuing `initial` with a particular locale beforehand may be necessary if the goal is to reset `stream` without changing its locale. I do not know whether doing this is more performant than creating a new ostringstream and imbuing it with a locale each time. – MikeOnline Dec 07 '22 at 17:42