Empty out an iostream and reuse it within a loop

C

Christopher

This question is asked the world over. I know I've asked it myself,
forgotten the answer and then asked it again. My colleagues ask it all
the time as well. I'd even request that this be added to the FAQ if it
isn't already. I looked it over and didn't find my answer there.

Anyway, question is:
How do you empty out and reuse an iostream inside a loop construct?

I know it was some magical combination of clear, flush, or
ostream::str(""); is some special order, but can't get it right again.

Example:

#include <iostream>
#include <sstream>

int main()
{
std::eek:stringstream os;
for(int i = 0; i < 5; i++)
{
// How to empty and reuse here?

os << i;
std::cout << "you are in iteration #" << os.str() << std::endl;

// Or is it done here?
}

return 0;
}
 
A

Alf P. Steinbach

* Christopher:
This question is asked the world over. I know I've asked it myself,
forgotten the answer and then asked it again. My colleagues ask it all
the time as well. I'd even request that this be added to the FAQ if it
isn't already. I looked it over and didn't find my answer there.

Anyway, question is:
How do you empty out and reuse an iostream inside a loop construct?

I know it was some magical combination of clear, flush, or
ostream::str(""); is some special order, but can't get it right again.

Example:

#include <iostream>
#include <sstream>

int main()
{
std::eek:stringstream os;
for(int i = 0; i < 5; i++)
{
// How to empty and reuse here?

os << i;
std::cout << "you are in iteration #" << os.str() << std::endl;

// Or is it done here?
}

return 0;
}

int main()
{
for(int i = 0; i < 5; i++)
{
std::eek:stringstream os;

os << i;
std::cout
<< "you are in iteration #" << os.str()
<< std::endl;
}
}

Alternatively you can use

o.str( "" ); o.clear();

before you reuse the stream. The textual position doesn't matter. What
matters is that this is executed before you reuse the stream.

However, reusing the stream -- or any variable, except one that is
very costly to construct -- isn't really a good idea.


Cheers, & hth.,

- Alf
 
C

Christopher

* Christopher:










int main()
{
for(int i = 0; i < 5; i++)
{
std::eek:stringstream os;

os << i;
std::cout
<< "you are in iteration #" << os.str()
<< std::endl;
}
}

Alternatively you can use

o.str( "" ); o.clear();

before you reuse the stream. The textual position doesn't matter. What
matters is that this is executed before you reuse the stream.

However, reusing the stream -- or any variable, except one that is
very costly to construct -- isn't really a good idea.

Cheers, & hth.,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?


Yes, that leads to my next question. It seems that some of my
colleagues are obsessed with a "Do not instantiate objects within a
loop, because it is more costly to performance" rule. I disagree with
this rule very much. I understand, if an object took minutes to
constructm, but simple data types like those in the STL? This bug was
introduced by said rule, because the ostringstream was declared within
the loop previously and worked fine, then someone moved it.

Is it not just as costly to call ostringstream.str("") as constructing
a new ostringstream? If not, isn't the difference negligible?

Thanks for the helps!
 
J

James Kanze

* Christopher:

You don't.

There is no str() function in ostream. Only in ostringstream.
int main()
{
for(int i = 0; i < 5; i++)
{
std::eek:stringstream os;
os << i;
std::cout
<< "you are in iteration #" << os.str()
<< std::endl;
}
}
Alternatively you can use
o.str( "" ); o.clear();
before you reuse the stream. The textual position doesn't
matter. What matters is that this is executed before you
reuse the stream.

You also have to set all of the other flags to their default
values, or expect surprises. (I'm not sure, but you may have to
seek as well.) Your proposed solution is much easier, and
cleaner: if you want a new stream, then create a new stream.
However, reusing the stream -- or any variable, except one
that is very costly to construct -- isn't really a good
idea.

You mean that reusing it isn't a good idea unless the profiler
says you have to.
 
J

James Kanze

* Christopher:
[...]
Yes, that leads to my next question. It seems that some of my
colleagues are obsessed with a "Do not instantiate objects within a
loop, because it is more costly to performance" rule. I disagree with
this rule very much. I understand, if an object took minutes to
constructm, but simple data types like those in the STL? This bug was
introduced by said rule, because the ostringstream was declared within
the loop previously and worked fine, then someone moved it.

I presume that that person has since been fired for
incompetence.
Is it not just as costly to call ostringstream.str("") as
constructing a new ostringstream? If not, isn't the difference
negligible?

It depends on the implementation. If there's no performance
problem, do whatever is cleanest. If there is a performance
problem, use the profiler to see where it's coming from. If it
is due to the constructor of std::eek:stringstream (which I doubt
is the case very often), then you might try the alternative, to
see if it helps. It might (but it's certainly not guaranteed).
 
A

Alf P. Steinbach

* James Kanze:
You don't.


There is no str() function in ostream. Only in ostringstream.







You also have to set all of the other flags to their default
values, or expect surprises.

For completeness, please show code.

(I'm not sure, but you may have to
seek as well.)

After o.str("") there isn't more than one possible position. If this
operation doesn't affect position, then the streams must be even worse
than I thought... :)

Your proposed solution is much easier, and
cleaner: if you want a new stream, then create a new stream.
Yep.



You mean that reusing it isn't a good idea unless the profiler
says you have to.

No, I meant what I wrote. For micro-level optimizations profiling or at
least measuring in /some/ way is the fundamental guiding principle, and
far too often neglected. For high level inefficiency avoidance,
however, common sense must be applied, in the same way that you don't
drive recklessly into a brick walls etc. in the belief that only post
catastrophe measurements can tell you whether that was a good idea.
Reusing a stringstream is not high level inefficiency avoidance, it is a
micro-level optimization that is to be avoided. Reusing something that
kicks off a process or makes a network connection at creation, if it can
be fairly easily reused, may on the other hand be practically necessary,
and I'd even extend that down to reusing a large memory allocation.

Cheers,

- Alf
 
A

Alf P. Steinbach

* werasm:
In the land of the blind the one eyed is KING ;-)

In the land of the blind the one eyed is accused of being a sabotaging
witch, because when he or she warns that someone will hurt themselves if
they do X and they do X and are hurt then it's obviously sabotaging
witchcraft, fails the water test (if you drown you're not a witch, if
you survive you're a witch), and is summarily burned at the stake.

Cheers,

- Alf
 
J

James Kanze

* James Kanze:

[...]
For completeness, please show code.

And how do I know that any code I would show would be complete?

My point is only that an iostream contains a lot of state. A
very lot. And that the above doesn't begin to return all of
that state back to its initial state. Some of the state is
probably irrelevant (e.g. tie()), but how can we be sure,
without seeing the user code. Other state (e.g. fmtflags) is
very definitly not irrelevant.
After o.str("") there isn't more than one possible position.
If this operation doesn't affect position, then the streams
must be even worse than I thought... :)

I don't know how they behave when you use them in ways for which
they weren't designed:).

[...]
No, I meant what I wrote.

In which case, I'm not sure what you meant. I've heard some
people claim that an std::eek:stringstream is very costly to
construct. Of course, I've also heard the same thing about
std::string. Even though the actual benchmark I ran showed that
reusing the same object was actually more expensive.

So I'm not really sure what you meant by "very costly to
construct". And of course, you have to consider the cost of
the alternative, as well; reuse isn't necessarily free.
For micro-level optimizations profiling or at least measuring
in /some/ way is the fundamental guiding principle, and far
too often neglected. For high level inefficiency avoidance,
however, common sense must be applied, in the same way that
you don't drive recklessly into a brick walls etc.

I can buy the "common sense" argument where a big-O difference
is involved, and you know up front that there will be a large
number of data. But it stops there.
in the belief that only post catastrophe measurements can tell
you whether that was a good idea. Reusing a stringstream is
not high level inefficiency avoidance, it is a micro-level
optimization that is to be avoided.

So it comes down to: what do you mean by "very costly to
construct"? Several seconds CPU?
Reusing something that kicks off a process or makes a network
connection at creation, if it can be fairly easily reused, may
on the other hand be practically necessary,

OK. I/O or external events are several orders of magnitude
slower than interal processing. Generally. Obviously, you'd
have to be sure that the clear operation didn't also do this
sort of thing, or you'd have gained nothing.
and I'd even extend that down to reusing a large memory
allocation.

That sounds like std::string. Allocation with modern allocators
isn't all that expensive.
 
A

Alf P. Steinbach

* James Kanze:
* James Kanze:
* Christopher:
[...]
Alternatively you can use
o.str( "" ); o.clear();
before you reuse the stream. The textual position doesn't
matter. What matters is that this is executed before you
reuse the stream.
You also have to set all of the other flags to their default
values, or expect surprises.
For completeness, please show code.

And how do I know that any code I would show would be complete?

My point is only that an iostream contains a lot of state. A
very lot. And that the above doesn't begin to return all of
that state back to its initial state. Some of the state is
probably irrelevant (e.g. tie()), but how can we be sure,
without seeing the user code. Other state (e.g. fmtflags) is
very definitly not irrelevant.

What of this to reset depends on what the programmer wants to reset or
to keep, and on what has been changed.

I don't know how they behave when you use them in ways for which
they weren't designed:).

I'm sorry, but it's incorrect that using str( s ) is to "use them in a
[a way] for which they weren't designed".

And I'm sorry, but it's also incorrect that I am the one doing that.

Since neither implication of your statement is true, I must regrettably
conclude that you're trying a bit of misdirection and projection.

[...]
No, I meant what I wrote.

In which case, I'm not sure what you meant. I've heard some
people claim that an std::eek:stringstream is very costly to
construct. Of course, I've also heard the same thing about
std::string. Even though the actual benchmark I ran showed that
reusing the same object was actually more expensive.

So I'm not really sure what you meant by "very costly to
construct".

I wrote "reusing the stream isn't really a good idea". What part of
that didn't you understand?

I also wrote "or any variable, except one that is very costly to
construct". What part of that didn't you understand?

Inconsistently, while above you're confusing what can be a good idea to
reuse with what is definitely not, below it seems you have grokked it:


[snip]
OK. I/O or external events are several orders of magnitude
slower than interal processing. Generally. Obviously, you'd
have to be sure that the clear operation didn't also do this
sort of thing, or you'd have gained nothing.

May I suggest you edit your articles for consistency (see above) before
posting. Pretending you have misunderstood a statement, just in order
to add misdirection and projecting false impressions, then afterward
showing you had no misunderstanding, is too revealing. Be consistent.

That sounds like std::string. Allocation with modern allocators
isn't all that expensive.

Sufficiently large allocations are generally expensive regardless of the
allocator. Blanket statements about allocation costs with modern
allocators are meaningless.

Grumble,

- Alf
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top