612

I've tried several things already,

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

both of which don't work.

1
  • Good guesses as those words can be verbs that mean what you want. But, the function to clear an sstream is named the same as the function that reads it: str ... not even a word! Isn't C++ beautiful? Commented Jan 3 at 13:08

12 Answers 12

958

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.

Sign up to request clarification or add additional context in comments.

13 Comments

Here is what happens when you forget the "clear()" part. stackoverflow.com/q/2848087/635549
@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.
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.
Oh boy is this intuitive. Just like everything else about C++!
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.
|
80

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.

16 Comments

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.
Feature still missing in GNU g++ v4.8, see stackoverflow.com/questions/24429441/…
@101010: How is swapping better than move-assignment?
This is low effecient. When I want to re use original ss. It swaps an empty for me.
@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.
|
47

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

m=std::stringstream();

9 Comments

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
I ran into the same problem, for me mm.clear(); mm.str(""); did the trick. (no C++11, else swap would be better).
@hochl: Why would swap be better than move-assignment?
It's not good for all situation. This would re-allocate the buffer every time while mm.str("") would not.
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.
|
40
m.str("");

seems to work.

2 Comments

That would be cleared by .clear() which is specified in the OP.
@Dave Lugg In case you didn't notice, this answer is from the original poster. Not sure what "that" refers to. clear() does not clear the content. This answer is correct ... except apparently you should also clear() (to clear the error state).
18

I am always scoping it:

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

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

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

2 Comments

Is this better than clearing the stringstream?
@Robur_131 There's not objective way to answer whether this approach is better than clearing the object. But, IMO this is the easiest to read and maintain.
16

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";

1 Comment

I found .str(""); will clear the stringstream and it won't reads input; I tried to use .clear() following .str(""); and solve the problem. Thanks for your answer.
4

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.

1 Comment

I upvoted this answer but then discovered that it does not actually set current size to zero, so the old content still visible: godbolt.org/z/erP8dMcfK
1

@Azeem's answer should be considered the best solution here. On the one hand his answer doesn't address the specific words of the OP's question, but on the other hand I think it addresses the intent of the OP's question. Excerpting @Azeem's code:

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

Benefits of using scoping contexts:

  • Reusing a variable is a code smell, so you should avoid doing it whenever possible. https://maximilianocontieri.com/code-smell-107-variables-reuse
  • When the context scope is entered you're guaranteed to have a new instance that's correctly initialized.
  • When the context scope is exited the instance is guaranteed to be destroyed correctly and all the memory is reclaimed.
  • It doesn't require knowing how a stringstream is implemented (buffer, pointer, index, etc). If you find that you need to know how a class is implemented, then either the class interface has been poorly designed, or you're just using the class wrong -- and that makes your code poorly designed.
  • It relies on the stringstream's constructor and destructor to do the right thing (code that's been thoroughly tested and debugged) instead of relying on code that you just wrote to do the right thing.
  • It's easy to type, easy to read, easy to understand: just two braces for each context.

Drawbacks:

  • You have to learn about contexts / blocks / scopes. https://en.cppreference.com/w/cpp/language/scope. There, you're finished.
  • It seems like it would require extra CPU cycles in order to create a new stringstream and then destroy it once for each context. That's fine, though. Your whole program uses extra CPU cycles. Don't count cycles (or even think about them) until you've proven empirically that you're running out of them.

2 Comments

You are right. Restrict the scope of each variable and never reuse a variable related to a string, because strings are inherently immutable.
@Jeff FWIW I see no answer from Azeem, but they did edit an answer from TimoK that includes code that looks like what included in this answer.
0

These 2 functions generate identical code for me on compiler explorer when using clang but with gcc the swap version results in much less assembly. Either way I think this empty initializer method should be considered for being the easiest to read.

void ClearEmptyBraces(std::stringstream& ss) {
    ss = { };
}

void ClearSwap(std::stringstream& ss) {
    std::stringstream().swap(ss);
}

Comments

0

The shortest and the most intuitive one.

m = {};

2 Comments

Interesting. What does this do exactly? Same as "m = std::ostringstream()"? ... And since I have to ask it's not intuitive to me. But maybe that's due to my ignorance of the language. I am familiar with "={}" for initialization, but I didn't know it could be used for assignment.
@steve: Yes, they are equivalent.
-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.

1 Comment

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.
-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();

3 Comments

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.
This solution does NOT work for Microsoft Visual C++.
Incorrect. Clear would be operating on the string returned from the stream, not the stream itself.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.