122

I'd like to clear out and reuse an ostringstream (and the underlying buffer) so that my app doesn't have to do as many allocations. How do I reset the object to its initial state?

Diego Sevilla
  • 28,636
  • 4
  • 59
  • 87
twk
  • 16,760
  • 23
  • 73
  • 97
  • possible duplicate of [In C++, how do you clear a stringstream variable?](http://stackoverflow.com/questions/20731/in-c-how-do-you-clear-a-stringstream-variable) – mpromonet Oct 19 '14 at 13:36

4 Answers4

163

I've used a sequence of clear and str in the past:

// clear, because eof or other bits may be still set. 
s.clear();
s.str("");

Which has done the thing for both input and output stringstreams. Alternatively, you can manually clear, then seek the appropriate sequence to the begin:

s.clear();
s.seekp(0); // for outputs: seek put ptr to start
s.seekg(0); // for inputs: seek get ptr to start

That will prevent some reallocations done by str by overwriting whatever is in the output buffer currently instead. Results are like this:

std::ostringstream s;
s << "hello";
s.seekp(0);
s << "b";
assert(s.str() == "bello");

If you want to use the string for c-functions, you can use std::ends, putting a terminating null like this:

std::ostringstream s;
s << "hello";
s.seekp(0);
s << "b" << std::ends;
assert(s.str().size() == 5 && std::strlen(s.str().data()) == 1);

std::ends is a relict of the deprecated std::strstream, which was able to write directly to a char array you allocated on the stack. You had to insert a terminating null manually. However, std::ends is not deprecated, i think because it's still useful as in the above cases.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • I am trying to use s.str() with an ostream. The size is messing it up (i can see the first character is null but it prints much more). Is there a good way to fix the str length? i am using s.str().c_str(); ATM and it works nicely –  Jun 06 '11 at 16:09
  • Actually even this isnt correct. I just did `s.str("");` instead. `auto str = s.str(); auto cstr = str.c_str(); file << cstr; s.clear(); s.seekp(0); s << ends;` –  Jun 06 '11 at 16:20
  • the std::ends doesn't work for me in google test `boost::any a = 1; std::ostringstream buffer; buffer << a << std::ends; EXPECT_EQ( buffer.str(), "any<(int)1>" );` `TestUtilsTest.cpp:27: Failure Expected: buffer.str() Which is: "any<(int)1>\0" To be equal to: "any<(int)1>"` and if I reuse with different length strings I get left over bits – David van Laatum Jun 27 '17 at 07:48
  • 1
    The Alternative is the true answer if you want to avoid reallocation. And if you want to truly "start fresh" without reallocation just call seekp(0) again after sending std::end. `s.seekp(0); s << std::ends; s.seekp(0);` – Chip Grandits Jun 30 '17 at 17:35
6

Seems to be that the ostr.str("") call does the trick.

Diego Sevilla
  • 28,636
  • 4
  • 59
  • 87
  • 11
    Worth pointing out that this won't re-use the underlying buffer from the ostringstream - it just assigns a new buffer. So while you're reusing the ostringstream object, you're still allocating two buffers. I don't think ostringstream is designed for reuse in the manner you intend. – razlebe Mar 08 '09 at 21:09
  • 2
    It also doesn't clear out the state, which is what .clear() does. I agree, it really isn't meant to be used like this. Just create a new one to be sure. Only if you profile will you find out if it makes any difference. – Brian Neal Mar 09 '09 at 02:30
  • 1
    sgreeve, Brian, that's right. Note, however, how the litb's method above requires of the usage of std::ends. It reuses the buffer, but makes you code differently as usual with stringstreams (normally you don't use std::ends). – Diego Sevilla Mar 09 '09 at 08:21
2

If you're going to clear the buffer in a way that will cause it to be cleared before it's first use, you'll need to add something to the buffer first w/ MSVC.

struct Foo {
    std::ostringstream d_str;
    Foo() { 
        d_str << std::ends;   // Add this
    }
    void StrFunc(const char *);
    template<class T>
    inline void StrIt(const T &value) {
        d_str.clear();
        d_str.seekp(0);  // Or else you'll get an error with this seek
        d_str << value << std::ends;
        StrFunc(d_str.str().c_str());  // And your string will be empty
    }
};
mpromonet
  • 11,326
  • 43
  • 62
  • 91
Unkle George
  • 126
  • 1
  • 3
  • I'm not seeing the failing behavior on VS2012. Furthermore, calling [`clear`](http://www.cplusplus.com/reference/ios/ios/clear/) will _cause_ the `failbit` to be set if the stream is empty. While just calling [`seekp`](http://www.cplusplus.com/reference/ostream/ostream/seekp/) should simply return if no stream exists. – Jonathan Mee Jul 08 '14 at 11:42
-2

You don't. Use two differently named streams for clarity and let the optimizing compiler figure out that it can reuse the old one.

Nicolás
  • 7,423
  • 33
  • 35
Sebastian Ganslandt
  • 965
  • 2
  • 13
  • 26
  • 5
    consider the use case where the code is looping over input data, writing to an `ostringstream` (based on the data read) and then has to write the string built in the `ostringstream` somewhere from time to time (e.g. after a certain character sequence was read) and start building a new string. – Andre Holzner Jan 31 '12 at 15:09