0

I tried to make the code #1 more terse by changing it to code #2 but it doesn't work as expected. Can anyone please tell me why it doesn't work? Thanks.

Code #1

double x = 8.9, y = 3.4, z = -4.5;
std::ostringstream q0;
q0 << "(" << x << "," << y << "," << z << ")";
std::string s = q0.str();


Code #2

double x = 8.9, y = 3.4, z = -4.5;
std::string s = static_cast<std::ostringstream &>(
  std::ostringstream() << "(" << x << "," << y << "," << z << ")").str();


Daniel Daranas
  • 22,454
  • 9
  • 63
  • 116
Dony
  • 45
  • 4

6 Answers6

7

I've reproduced your garbage. The only thing I can think of is that your static cast is invalid. That seems really odd to me but it's the only thing I can think might be happening. It could be that op<< returns something other than ostringstream that is not castable to ostringstream...like a reference stream of some sort. In fact, when assigning the reference to a variable and looking at the type in a debugger, it looks weird for a ostringstream.

At any rate, there's no reason to be "terse". In fact, being terse is often quite annoying to other developers who have to read your code. If you want to be "terse", put you stream stuff in a function that returns a string and name it something useful.

Edit:

Actually, I think I may have a better answer. You're binding a non-const reference to a temporary and calling a function on it. A const reference is guaranteed to continue existing until the end of the 'statement' (forgetting the technical term right now but it's close). A non-const reference does not have this guarantee. Therefore I think you are eliciting undefined behavior when you call str() on this non-const reference because the compiler is free to delete the temporary it refers to.

Edward Strange
  • 40,307
  • 7
  • 73
  • 125
  • I don't think either of these answers is correct. I tried dynamic_cast and it did not throw or change output. I tried const& and it also did not alter anything. Don't know what you're running into, could simply be a compiler bug. My advice stands though. – Edward Strange Mar 29 '10 at 16:53
  • The temporary being optimized away would make sense to me. If you do the code below and allocate on the heap and do a memory leak, you don't have the error. std::string s = static_cast(*(new std::ostringstream()) << "(" << x << "," << y << "," << z << ")").str(); – Bill Lynch Mar 30 '10 at 04:04
  • You could be right but after looking up the rules for temporary lifetimes I don't believe the compiler is free to do that. Optimizing something away is not supposed to change well defined behavior. If, as I believe is true, the statement is well defined then this would be a compiler bug. – Edward Strange Mar 30 '10 at 19:29
  • The temporary lifetime is up to the end of the full expression, which in this case is the semicolon and *after* the string has been copied. There is no lifetime issues in the code. – David Rodríguez - dribeas Dec 12 '12 at 20:24
3

You may want to use the code provided in this answer.

Community
  • 1
  • 1
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
3

I asked a similar question a while ago. The answers explain why what you've done doesn't work (you might have encountered either compile-time errors or printing strings as hex addresses like I did), and how to get around it (Johannes Schaub posted a very nice workaround using getlval()).

Community
  • 1
  • 1
AshleysBrain
  • 22,335
  • 15
  • 88
  • 124
  • I am getting hex addresses at the output. – Dony Mar 29 '10 at 17:02
  • The workarounds Johannes has suggested seem to work but I am still interested in knowing why what I tried didn't work. – Dony Mar 29 '10 at 17:03
  • @Dony: Tronic's answer to AshleysBrain's question, and especially Tronic's comment below his answer, give more details as to why your code isn't working. It can't pass the temporary `ostringstream` to `ostream &operator<<(ostream &, char const *)`, since you can't bind a temporary to a non-const reference. However, it can pass the `ostringstream` to `ostream &ostream::operator<<(void const *)`, since that function is a member function and it's legal to call a member function of a temporary variable. The `void const *` version of the function prints the pointer as a hex value. – Josh Townzen Mar 30 '10 at 05:49
1

If you have access to the boost format library, the following could be considered more "terse".

cout << boost::format("writing %1%,  x=%2% : %3%-th try") % "toto" % 40.23 % 50;
Bill Lynch
  • 80,138
  • 16
  • 128
  • 173
1

You have the answer as to "why" above which has been addressed.

A quick suggestion is that you can always make your thing work by substituting ostringstream() with ostringstream().flush(). That makes the result eligible for ref-to-non-const binding.

Gilles 'SO- stop being evil'
  • 104,111
  • 38
  • 209
  • 254
igorlord
  • 376
  • 3
  • 4
0

Some of the ostream operator<< overloads — in particular those for std::string and char const* are free functions, like:

ostream& operator<<(ostream& os, T const&);

If the stream is a temporary (which in your case it is), it cannot bind to that ref-to-non-const, and the overload cannot be chosen.

So you are instead accidentally using a non-preferred overload by accident; in this case, the overload for void const*. That's why you're seeing pointer contents (it's not "garbage").

This is a limitation when trying to do this serialisation on a single line, and you can't get around it.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055