I have to send the same string (e.g. a log message) to multiple streams.
Which of the following solutions is the most efficient?
Rebuild the same string for each stream and send it to the stream itself.
outstr1 << "abc" << 123 << 1.23 << "def" << endl; outstr2 << "abc" << 123 << 1.23 << "def" << endl; outstr3 << "abc" << 123 << 1.23 << "def" << endl;
Build the string once with string's operators, and send it to all the streams.
std::string str = "abc" + std::to_string(123) + std::to_string(1.23) + "def"; outstr1 << str; outstr2 << str; outstr3 << str;
Build the string once with a stream, and send it to all the streams:
std::stringstream sstm; sstm << "abc" << 123 << 1.23 << "def" << endl; std::string str = sstm.str(); outstr1 << str; outstr2 << str; outstr3 << str;
Some or all of these output streams could be on a RAM disk.
Any other ways to do the same thing?
The "proper" way to do something like this is to have a stream buffer writing to multiple destinations and use this stream buffer via a
std::ostream
. This way the code looks as if it writing just once but the characters are sent multiple times. Searching for "teebuf Dietmar" will find a few variations on the same theme.To also comment on your question: Which one of the three alternatives is the fastest depends on the exact expressions you have:
std::string
. I'd expect this to be slowest.std::ostringstream
) and allocates some memory. Out of your options I'd expect it to be fastest.Using a
teebuf
is probably fastest, at least, when it does some buffering but uses only fixed suze arrays, both for the buffer and the array of stream buffer pointers. Note, that you'll need to overridesync()
to deal with the buffer in a timely manner, though.To determine the actual performance you'll need to measure!
I would use a tee output stream. Do something like (pseudocode):
There doesn't seem to be anything in the standard c++ library to do this, but Boost has one.
See also the answers to How can I compose output streams, so output goes multiple places at once?
Although it is unlikely that you would see much difference either way1, option #3 sounds the most plausible: unlike the first option, it does not convert
int
s tostring
s multiple times; unlike the second option, it does not allocate and delete multiplestring
objects for its intermediate results2. It also looks cleanest from the readability point of view: no code is duplicated, and output looks like an output, not like a concatenation.1 Insert a mandatory disclaimer about optimization before profiling being evil here.
2 Small String Optimization may help on systems where it is supported (thanks, Prætorian), but the constructor and destructor calls for the intermediate objects are not going away.