585

I've tried several things already,

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

both of which don't work.

BartoszKP
  • 34,786
  • 15
  • 102
  • 130
CodingWithoutComments
  • 35,598
  • 21
  • 73
  • 86

9 Answers9

919

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.

BartoszKP
  • 34,786
  • 15
  • 102
  • 130
Wilka
  • 28,701
  • 14
  • 75
  • 97
  • 134
    Here is what happens when you forget the "clear()" part. http://stackoverflow.com/q/2848087/635549 – galath Jun 17 '12 at 19:17
  • why is it that the m.str() returns the string values but does not clear the stream? – Kshitij Banerjee Jul 05 '12 at 11:22
  • 8
    @KshitijBanerjee I think in C++ m.str() and m.str("") are two different functions. m.str() invokes a function which didn't expect any parameter whereas m.str("") will invoke the function which accepts a const char* parameter. m.str() might have been implemented as a **get** function which returns the string whereas m.str("") might have been implemented as a **set** function. – Dinesh P.R. Jul 18 '12 at 05:41
  • Following link neatly documents both versions of str http://en.cppreference.com/w/cpp/io/basic_stringstream/str – wardw Sep 17 '12 at 14:34
  • 4
    As galath said it is very important also to add m.clear(); in addition to m.str("");. Otherwise you can get problems if at some point you fill the stringstream with an empty string. – Sputnik Oct 20 '15 at 16:45
  • something weird is happening. After clearing a stringstream with str(""), the stringstream is unable to be set with more data> example: std::stringstream ss; ss << "test"; ss.str(""); ss << "test2"; after this last statement, ss is empty. – James May 22 '17 at 20:06
  • @James is this really your full context? Your snippet works as expected here: https://wandbox.org/permlink/PX6ISZbFNpaejfYW – arthropod Jun 02 '18 at 18:48
  • 1
    @anthropod Yes that was last year. I have since gotten it working. – James Jun 03 '18 at 19:08
  • 7
    Oh boy is this intuitive. Just like everything else about C++! – sunny moon Nov 29 '19 at 15:55
  • Does `m.str(std::string());` throw? – Mayur Apr 23 '21 at 17:18
  • You might want to add a comment that it's completely un-intuitive that `m.str("foo"); m.str << "bar"` does not return "foobar" – gman Aug 20 '21 at 17:51
  • This is the worst accepted AND upvoted answer in Stackoverflow i came across so far. In my std library implementation the stringstream was unusable after this reset. Just use m=std::stringstream(); from the answer of jerron. – Niceman Mar 12 '23 at 18:03
73

You can clear the error state and empty the stringstream all in one line

std::stringstream().swap(m); // swap m with a default constructed stringstream

This effectively resets m to a default constructed state, meaning that it actually deletes the buffers allocated by the string stream and resets the error state. Here's an experimental proof:

int main ()
{
    std::string payload(16, 'x');
    
    std::stringstream *ss = new std::stringstream; // Create a memory leak
    (*ss) << payload;                              // Leak more memory
    
    // Now choose a way to "clear" a string stream
    //std::stringstream().swap(*ss); // Method 1
    //ss->str(std::string());        // Method 2
    
    std::cout << "end" << std::endl;
}

Demo

When the demo is compiled with address sanitizer, memory usage is revealed:

=================================================================
==10415==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 392 byte(s) in 1 object(s) allocated from:
    #0 0x510ae8 in operator new(unsigned long) (/tmp/1637178326.0089633/a.out+0x510ae8)
    #1 0x514e80 in main (/tmp/1637178326.0089633/a.out+0x514e80)
    #2 0x7f3079ffb82f in __libc_start_main /build/glibc-Cl5G7W/glibc-2.23/csu/../csu/libc-start.c:291

Indirect leak of 513 byte(s) in 1 object(s) allocated from:
    #0 0x510ae8 in operator new(unsigned long) (/tmp/1637178326.0089633/a.out+0x510ae8)
    #1 0x7f307b03a25c in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::reserve(unsigned long) (/usr/local/lib64/libstdc++.so.6+0x13725c)
    #2 0x603000000010  (<unknown module>)

SUMMARY: AddressSanitizer: 905 byte(s) leaked in 2 allocation(s).

Pretty steep if you ask me. To hold just 16bytes of payload, we spent 905 bytes ... string streams are no toy. Memory is allocated in two parts:

  • The constructed string stream (392 bytes)
  • The extra buffer needed for the payload (513 bytes). The extraneous size has to do with the allocation strategy chosen by the stream and for payloads <= 8 bytes, blocks inside the initial object can be used.

If you enable method 1 (the one shown in this answer) the extra 513 (payload) bytes are reclaimed, because the stream is actually cleared.

If you enable method2 as suggested in the comments or other answers, you can see that all 905 bytes are in use by the time we exit.

In terms of program semantics, one may only care that the stream "appears" and "behaves" as empty, similar to how a vector::clear may leave the capacity untouched but render the vector empty to the user (of course vector would spend just 16 bytes here). Given the memory allocation that string stream requires, I can imagine this approach being often faster. This answer's primary goal is to actually clear the string stream, given that memory consumption that comes with it is no joke. Depending on your use case (number of streams, data they hold, frequency of clearing) you may choose the best approach.

Finally note that it's rarely useful to clear the stream without clearing the error state and all inherited state. The one liner in this answer does both.

Nikos Athanasiou
  • 29,616
  • 15
  • 87
  • 153
  • 5
    This is the most efficient and most elegant way to do it compared to all other answers here. However, std::stringstream::swap is a c++11 feature and this solution doesn't work for prior c++11 compilers. – 101010 Nov 03 '14 at 09:48
  • 5
    Feature still missing in GNU g++ v4.8, see http://stackoverflow.com/questions/24429441/c-compiler-does-not-recognize-stdstringstreamswap – Joachim W Nov 11 '14 at 16:11
  • 9
    @101010: How is swapping better than move-assignment? – Deduplicator Dec 02 '15 at 19:27
  • @Deduplicator - swap is noexcept – Aset D Jun 30 '17 at 13:55
  • 3
    @AsetD: Even if it is noexcept, did you forget the default-constructed temporary? – Deduplicator Jun 30 '17 at 14:00
  • 6
    This is low effecient. When I want to re use original ss. It swaps an empty for me. – Zhang Dec 11 '18 at 05:23
  • 5
    @101010 I would expect this to be much *less* efficient that calling `m.str({})`, as Zhang's comment said. To clarify: When you call `m.str({})` I would expect that it would reuse some of the memory it allocated during the first operation to speed up the next operation. When you call `std::stringstream().swap(m)` I expect any memory it allocated during the first operation would have its ownership transferred to the temporary you just created, losing the chance for that efficiency. It would interesting to see a comparison in practice though. – Arthur Tacca Mar 05 '19 at 10:02
  • 3
    might as well just do `m = std::stringstream();` rather than swapping with an object you're deleting – Puddle May 31 '19 at 14:30
  • I think this causes memory leak as the original `m` 's memory address will be left in the memory without destruction. The `stringstream()` construct creates a new object and swaps it with `m`. – shaheen g Nov 18 '20 at 23:22
  • I think `swap` is a good general solution because streams can have a lot of internal state. Regarding temporaries, I would expect the compiler to eliminate them. And allocation is fraught; eschew pre-optimization. I would expect allocation to typically be pointer fiddling. – John H. Feb 16 '21 at 16:51
  • 1
    @shaheeng That is wrong. The old `m` gets swapped into the unnamed temporary, which is destructed at the end of the statement and thus frees all resources previously owned by `m`. Or if you meant the assignment from a default-constructed instance, then the assignment operator is specified not to leak (because why would it?). Nothing is "left in the memory without destruction". C++ with its RAII ensures things are destroyed automatically when appropriate, unless you go out of your way to allocate manually and don't free, but you should just not do that. – underscore_d Sep 25 '21 at 14:06
  • I believe that in my system, this statement executed more slowly than the `m.str(std::string())` version. However, I left out the `m.clear()`, so that could also be a contributor – mattgately Nov 17 '21 at 12:46
  • 1
    @mattgately There's more things involved in choosing a proper method. Probably that's why the standard does not provide a `reset` function (yet). I've updated my answer to hint at more factors that may affect your choice. As stated among others it's hardly useful to clear the stream without clearing the error state. Then there's the memory consideration. – Nikos Athanasiou Nov 17 '21 at 20:40
  • But isn't the whole point of clearing a stringstream avoiding the construction of a new one? – einpoklum Dec 22 '21 at 13:30
  • @einpoklum If you opt for `m.str("")`, just remember to clear the state, [this](https://stackoverflow.com/q/2848087/2567683) may happen if you don't (when I say state, I mean the error state and all inherited state - I couldn't guarantee those two are one and the same). I don't have extra remarks on the "whole point", all I (re)searched is shown in the answer. – Nikos Athanasiou Dec 22 '21 at 20:02
  • @NikosAthanasiou: Yes, I've been burned by this recently. I don't even like istringstreams, it's just that formatted input is such a mess in the standard library... a bunch of different partial facilities with overlaps and different paradigms... – einpoklum Dec 22 '21 at 20:29
44

This should be the most reliable way regardless of the compiler:

m=std::stringstream();
NullUserException
  • 83,810
  • 28
  • 209
  • 234
jerron
  • 457
  • 4
  • 2
  • 2
    This is better in my opinion because m.str(""); caused my stringstream to be stuck with that empty value whatever I tried. But using this I don't have that problem – gelatine1 May 25 '14 at 06:59
  • 3
    I ran into the same problem, for me `mm.clear(); mm.str("");` did the trick. (no C++11, else swap would be better). – hochl Aug 27 '15 at 11:42
  • 1
    @hochl: Why would `swap` be better than move-assignment? – Deduplicator Dec 02 '15 at 19:26
  • I guess that would be ok as well. If performance is important you may want to check which is faster and choose accordingly. – hochl Dec 04 '15 at 13:11
  • Almost certainly the fastest and best answer but requires C++11. – Nemo Oct 01 '16 at 22:04
  • 4
    It's not good for all situation. This would re-allocate the buffer every time while mm.str("") would not. – Shital Shah Dec 24 '16 at 01:29
  • 3
    My primary use-case for flushing a stringstream object is keeping a threadlocal stringstream object around to prevent unecessary instantiation of the stringstream -- instantiating a new stringstream object copies the global locale object -- theoretically this is quick and only involved incrementing an atomic, but at the level of concurrency I deal with it's often crippling. – Spacemoose Nov 17 '17 at 13:39
  • 1
    `use of deleted function ‘std::basic_stringstream& std::basic_stringstream::operator=(const std::basic_stringstream&)` – Rodrigo Gurgel Dec 22 '17 at 13:44
38
m.str("");

seems to work.

CodingWithoutComments
  • 35,598
  • 21
  • 73
  • 86
14

I am always scoping it:

{
    std::stringstream ss;
    ss << "what";
}

{
    std::stringstream ss;
    ss << "the";
}

{
    std::stringstream ss;
    ss << "heck";
}
Azeem
  • 11,148
  • 4
  • 27
  • 40
TimoK
  • 203
  • 2
  • 6
13

my 2 cents:

this seemed to work for me in xcode and dev-c++, I had a program in the form of a menu that if executed iteratively as per the request of a user will fill up a stringstream variable which would work ok the first time the code would run but would not clear the stringstream the next time the user will run the same code. but the two lines of code below finally cleared up the stringstream variable everytime before filling up the string variable. (2 hours of trial and error and google searches), btw, using each line on their own would not do the trick.

//clear the stringstream variable

sstm.str("");
sstm.clear();

//fill up the streamstream variable
sstm << "crap" << "morecrap";
Francisco Cortes
  • 1,121
  • 10
  • 19
3

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.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • 3
    I upvoted this answer but then discovered that it does not actually set current size to zero, so the old content still visible: https://godbolt.org/z/erP8dMcfK – 4LegsDrivenCat Nov 16 '22 at 20:45
-1

It's a conceptual problem.

Stringstream is a stream, so its iterators are forward, cannot return. In an output stringstream, you need a flush() to reinitialize it, as in any other output stream.

  • 3
    http://en.cppreference.com/w/cpp/io/basic_ostream/flush flush synchronizes with the storage device it's associated with. This is not the same reinitialization. – Clearer Nov 21 '14 at 11:09
-14

These do not discard the data in the stringstream in gnu c++

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

The following does empty the stringstream for me:

    m.str().clear();
John
  • 13
  • 1
  • 1
  • 7
    I'm not so sure this would work, because of the same reasons bernhardrusch's wouldn't work. The .str() function returns a copy, and clearing the copy wouldn't do anything. – Verdagon Mar 29 '13 at 21:22
  • 1
    This solution does NOT work for Microsoft Visual C++. – Zak Feb 21 '14 at 18:15
  • Incorrect. Clear would be operating on the string returned from the stream, not the stream itself. – Joey Carson Apr 30 '16 at 15:47