Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I create a temporary ostream using another's streambuf?

Suppose I have a function that takes an ostream & parameter o and writes to that ostream. An operator << implementation would be a good example.

ostream& operator << (ostream& o, const MyThing& t)
{
  // ... interesting code here ...
  return o;
}

Within the function, I might want to specify formatting options on the stream. For example, I might want a number to be printed as hex, no matter how the o is configured when it is passed in to the function.

Secondly, I might want to be able to make assumptions about the current formatting flags. For example, it would be nice to be able to assume that numbers were formatted as decimal unless I request otherwise.

Finally, by the time the function exits I want the formatting options on o to be the same as they were before the function was called, so as to appear unchanged to the caller. This is simply a matter of politeness to the caller.

Up until now I have achieved this by creating a local ostringstream within the function, doing all my work on that (including setting formatting options), and sending the .str() to o at the end of the function. The StackOverflow question here suggests that people cleverer than me take the same approach. However, it bothers me that I'm keeping so much data in ostringstreams that could perhaps be sent to the output earlier (the strings can get quite large).

I have two questions:

1) Is it legal, idiomatic, good form, etc. to create a temporary (stack based) ostream around o.rdbuf() and do my work on that ostream? My own tests and the page at cppreference.com appears to suggest that I can.

ostream& operator << (ostream& o_, const MyThing& t)
{
  ostream o (o_.rdbuf());
  // write stuff to "o",
  // setting formatting options as I go.
  return o_; // Formatting on the parameter ostream o_ unchanged.
}

2) Is there another, better way that I have not considered?

like image 683
peterpi Avatar asked Nov 06 '14 11:11

peterpi


2 Answers

Boost IO State Savers are built exactly for this purpose.

like image 69
John Zwinck Avatar answered Nov 15 '22 21:11

John Zwinck


That's not a bad solution; it's certainly legal. I don't think it's too common, so it's probably a good idea to comment as to why you're doing it.

The most frequent solution I've seen here is to create a state saver class, which will save all of the state you need (typically, flags(), precision() and fill()) in the constructor, and restore it in the destructor, and then to forceably set all of the options you want. (It may be possible to use copyfmt for this, although this also copies things like the exception mask, which you probably don't want to play with.)

like image 23
James Kanze Avatar answered Nov 15 '22 20:11

James Kanze