3

Something a lot of C++ programmers miss (read: me) when first using stringstreams is the fact that the copy returned by stringstream::str() is a temporary, which lasts until the end of the expression it's used in. However, I don't understand:

  1. How this is done. Looking in the sstream header for libstdc++, I only see a copy being made and returned. How is the lifetime restricted?
  2. Why this is the desired behavior, especially since it is such a common gotcha. If a copy is being made anyway, why can't I take ownership of it?

Note that this is not a duplicate of stringstream, string, and char* conversion confusion. That goes over explaining the behavior and workarounds; I'm looking for mechanics and rationale.

Community
  • 1
  • 1
scry
  • 1,237
  • 12
  • 29
  • 1
    I'm not sure what you're asking. `stringstream::str` returns a copy of the internal string, unless I'm missing something. – Collin Dauphinee Feb 03 '14 at 18:23
  • 1
    This problem exists with anything that returns a copy of something that gives access to a pointer to data. It just happens that going from `std::stringstream` to a `const char *` occurs more often than other cases. Anyway, you said the other answer explains behaviour, but you want mechanics. I'm not quite sure how to differentiate those. – chris Feb 03 '14 at 18:24
  • @dauphic I think I misunderstood what is copied - you're saying the `string` object is copied shallowly, so that the character array it points to is shared? – scry Feb 03 '14 at 18:31
  • @roysc: AlexTelishev's answer explains it. It returns a full copy of the internal string, which is valid until it is destroyed, but `c_str()`'s return value is only valid until the end of the expression. – Collin Dauphinee Feb 03 '14 at 18:32
  • I am a bit confused as to why so many answers talk about `c_str()`, I don't see that mentioned anywhere in your question? What is this expression they are talking about? `stringstream.str().c_str()`? Is this question about `str()` or `c_str()`? It sounds like it's mostly about `c_str()`. – jrh Nov 15 '20 at 23:57
  • @jrh I think it's just a common beginner mistake to try to use the `c_str` function on the returned `string`, and the answer was made under the assumption I was doing so. – scry Nov 18 '20 at 13:21
  • @scry ah I see. I searched for this looking for confirmation that `stringstream::str()` makes a copy of the character data in the `stringstream` and doesn't just reference it (making it okay to let the `stringstream` go out of scope after `str()` is called), it looks like that's the case. I didn't use `c_str()` at all. – jrh Nov 18 '20 at 13:48

3 Answers3

5

This is not a problem of stringstream. It is the problem of c_str function - it returns pointer to a char* representation of std::string, but it lives only during lifetime of an original string. When you call char *str = ss.str().c_str() the following actually happens:

string tmp = ss.str();
char *str = tmp.c_str();
tmp.~string (); // after that line the pointer `str` is no longer valid

c_str is a dangerous function provided only for compatibility and speed purposes and you should avoid using it.

David G
  • 94,763
  • 41
  • 167
  • 253
Alex Telishev
  • 2,264
  • 13
  • 15
  • I was misunderstanding the [str](http://en.cppreference.com/w/cpp/io/basic_stringstream/str) reference, and thinking there was something "special" about the object returned. This seems pretty obvious now. – scry Feb 03 '14 at 18:39
0

stringstream::str() returns a string. Period. It does so by value, so you can do whatever you want with it (e.g. certainly take ownership).

  • It's a temporary value. You can't even take its address. You have to copy it, the whole thing, if you want to use it after the end of the expression. – Blair Houghton Oct 07 '15 at 23:35
0

How this is done? Looking in the sstream header for libstdc++, I only see a copy being made and returned. How is the lifetime restricted?

str() returns by value, meaning the object it returns is destroyed by the end of the full expression. It's simply the way temporaries work.

Why this is the desired behavior, especially since it is such a common gotcha. If a copy is being made anyway, why can't I take ownership of it?

It's an amendment from the traditional IOStreams. The old deprecated class of streams strstream had an str() method that returned a pointer to its internal buffer. To protect against invalidation of the pointer, the stream had to be "frozen", meaning the buffer could not be resized.

The Standard IOStreams returns a copy of the buffer as a std::basic_string<charT> object so that freezing the stream is no longer necessary.

David G
  • 94,763
  • 41
  • 167
  • 253