2

I'm licking my wounds from Memory Error with std:ostringstream and -std=c++11?, and I have a related question.

If the following returns a temporary so that reserve has no effect and the char* is not valid:

ostringstream oss;
oss.str().reserve(96);

// populate oss

const char* ptr = oss.str().c_str();
// do something with ptr

Then how does the following clear the ostringstream (from How to reuse an ostringstream?):

oss.clear(); oss.str("");

I understand clear() will reset the stream's flags; but as I now understand str("") will operate on a temporary and not the underlying string.

So how does str("") reset the stream?

Community
  • 1
  • 1
jww
  • 97,681
  • 90
  • 411
  • 885

3 Answers3

4

These are different functions.

oss.str() (without parameters) returns a copy to the stream's underlying string, but oss.str("") sets its underlying string to the value you passed (here an empty string: "").

So calling both clear() and str("") on a std::stringstream actually kind of "resets" it.

Notice the two signatures on cppreference

JBL
  • 12,588
  • 4
  • 53
  • 84
  • `clear()` resets the error flags. `str("")` replaces the input data with the given string. The two are totally unrelated. – James Kanze Jan 22 '14 at 14:15
  • 2
    And to be exact: `oss.str()` returns a _copy_ of the stream's underlying string. In this case, the fact that it's a copy is important. – James Kanze Jan 22 '14 at 14:16
  • Thanks JBL. I can't tell you how many times I vistied a different CCP Reference page. I think its kind of crummy the C++ committee overloaded the the behavior and semantics of `.str()` (in one case a temporary, in another case a pseudo-reference). That's precisely why I thought `.str()` returned a reference to the underlying string. – jww Jan 22 '14 at 14:19
  • @JamesKanze Yep, it's a copy. I wrote "returns ... as a temporary" but it felt awkward, so I removed it, but forgot to mention it's a copy. I'll upvote your comment to stress that. – JBL Jan 22 '14 at 14:19
  • @noloader I think you misunderstand the behaviour of the function. There's no "pseudo-reference" as you call it. You are simply passing a string to `str` which then does the assignment to the internal object. At no point does the function give you the internal object. – Joseph Mansfield Jan 22 '14 at 14:21
  • @JamesKanze and yes, the two functions are unrelated, but both are used to create the impression of some kind of `reset()` function that leaves the stream in a empty and "clean" (for the lack of a better word) state. – JBL Jan 22 '14 at 14:21
  • @noloader In one case it returns nothing (when you _set_ the underlying string content), and in the other case, it returns by value ,which means you have a copy, nothing more. – JBL Jan 22 '14 at 14:23
  • Which is, I suppose, what you meant by "kind of". Neither, of course, actually resets the stream; they only reset a (relatively small) part of it. The only practical way to get a stream in a "like new" state is to create a new instance. – James Kanze Jan 22 '14 at 14:26
  • "In one case it returns nothing .. and in the other case, it returns by value..." - that's precisely the point I am trying to make. `str` has different behaviors and meanings depending on how its used. Pick a meaning and use it consistently. If you want two behaviors, then use two different functions names to avoid confusion. – jww Jan 22 '14 at 14:28
  • @JamesKanze Yes. But it's the closest (I believe, correct me if I'm wrong) we get to some kind of reset. – JBL Jan 22 '14 at 14:29
  • @JosephMansfield - "I think you misunderstand the behaviour of the function..." - yes, clearly ;) And it was happening for a long time.... – jww Jan 22 '14 at 14:32
  • 1
    @noloader Ah but whether or not this is confusing or not is a whole different debate! :P Then, when you say "`str` has different behaviors and meanings depending on how it's used", I'd say "there's two `str` functions, which one?". I got used to it so I don't really see an issue there, but I can understand the confusion it could create. – JBL Jan 22 '14 at 14:32
  • 1
    @noloader In this case, the committee simply adopted an ubiquitious C++ idiom: overloading functions with an attribute name, with a const version without parameters as the getter, and a non-const version with a new value as the setter. – James Kanze Jan 22 '14 at 15:14
3

Calling str with no argument returns a copy of the internal string object. That's why it's a temporary object. Calling str with a string argument sets the value of the internal string object. It doesn't work on a temporary object.

It seems like you're thinking of it like this:

oss.str() = "";

But that's not what it is. You're passing "" to the str function so that it can assign it to the internal string.

It's no different to any other getter/setter combination. If you have getX(), it typically gets you a copy of some member of the class you're calling it on. If you have setX(x), it typically sets the value of that member. In this case, they're just both called str, but one takes an argument and the other doesn't.

Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
  • "... it typically gets you a copy of some member of the class you're calling it on" - I actually learned it differently in college (20 years ago or so). If an copy was expensive, you return a reference, not a copy. A string is an expensive object because it requires a call to `new` and a call to `memcpy`. So you would provide a `const` and `non-const` version for `str()` (in my hypothetical and mis-informed case). – jww Jan 22 '14 at 14:22
2

From this std::ostringstream::str reference:

Parameters

new_str - new contents of the underlying string

It can be used to get the string, or to set the string to the string provided by the functions argument.

Community
  • 1
  • 1
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621