Why is boost::format::operator% not declared const?
Hello, I use boost::format to convert a float to a string: void CalledThousandsOfTimesPerSecond(float f) { GetStream() << boost::format("%0.3f") % f << GetSomeOtherContent(); } I normally would deal with something like this by adding a static const variable: void CalledThousandsOfTimesPerSecondFromManyThreads(float f) { static const boost::format Formatter("%0.3f"); GetStream() << Formatter % f << GetSomeOtherContent(); } But this does not work. boost::format::operator% is not declared const. Question 1: Why is boost::format::operator% declared mutable? What is is mutating? Question 2: How do I not spend overhead constructing the same boost::format thousands of times per second? Possible answers to question 2: void CalledThousandsOfTimesPerSecond(float f) { static boost::format Formatter("%0.3f"); // MUTABLE -- this might not be thread safe??? GetStream() << Formatter % f << GetSomeOtherContent(); } void CalledThousandsOfTimesPerSecond(float f) { static const boost::format Formatter1("%0.3f"); boost::format Formatter2(Formatter1); // lame but I guess it works GetStream() << Formatter2 % f << GetSomeOtherContent(); } Thank you, Chris
void CalledThousandsOfTimesPerSecondFromManyThreads(float f) { static const boost::format Formatter("%0.3f");
GetStream() << Formatter % f << GetSomeOtherContent(); }
I'm pretty sure boost::format is not thread safe
If you think about what it's doing, every time you call operator% it's inserting a formatted item into it's internal state. Think about what happens if you feed multiple elements via operator% and then call .str() - you get a std::string back - it has to store everything you've fed in internally so that you can access the formatted string later via .str()
On Tue, Jan 15, 2013 at 5:49 PM, Steve Lorimer
Think about what happens if you feed multiple elements via operator% and then call .str() - you get a std::string back - it has to store everything you've fed in internally so that you can access the formatted string later via .str()
Steve, Thank you. I never used boost::format::str, but I agree that its presence indicates that operator% must alter an internal state. Question 1: Is there an efficient way to do the following (and by "more efficient" I mean fewer format constructors and string parsing): void WriteLog(float x, float y, float z, const Employee& e) { std::cout << "Values: " << boost::format("%0.3") % x << e << boost::format("%0.3") % y << boost::format("%0.3") % z; } Question 2: Is there a more efficient way to do this: std::string FloatToString(float x, int DigitsAfterDecimal) { std::ostringstream FormatStream; FormatStream << "%0." << DigitsAfterDecimal; boost::format Formatter(FormatStream.str()); Formatter % x; return Formatter.str(); } Thank you, Chris
2013/1/16 Chris Stankevitz
On Tue, Jan 15, 2013 at 5:49 PM, Steve Lorimer
wrote: Think about what happens if you feed multiple elements via operator% and then call .str() - you get a std::string back - it has to store everything you've fed in internally so that you can access the formatted string later via .str()
Steve,
Thank you. I never used boost::format::str, but I agree that its presence indicates that operator% must alter an internal state.
Question 1: Is there an efficient way to do the following (and by "more efficient" I mean fewer format constructors and string parsing):
void WriteLog(float x, float y, float z, const Employee& e) { std::cout << "Values: " << boost::format("%0.3") % x << e << boost::format("%0.3") % y << boost::format("%0.3") % z; }
Hi, I'm no expert here, but I'd try this: boost::format const fmt("%0.3" ); cout << boost::format(fmt) % x << e << boost::format(fmt) %y ... HTH, Kris
On 1/16/2013 2:47 AM, Chris Stankevitz wrote:
On Tue, Jan 15, 2013 at 5:49 PM, Steve Lorimer
wrote: Think about what happens if you feed multiple elements via operator% and then call .str() - you get a std::string back - it has to store everything you've fed in internally so that you can access the formatted string later via .str()
Steve,
Thank you. I never used boost::format::str, but I agree that its presence indicates that operator% must alter an internal state.
Question 1: Is there an efficient way to do the following (and by "more efficient" I mean fewer format constructors and string parsing):
void WriteLog(float x, float y, float z, const Employee& e) { std::cout << "Values: " << boost::format("%0.3") % x << e << boost::format("%0.3") % y << boost::format("%0.3") % z; }
Question 2: Is there a more efficient way to do this:
std::string FloatToString(float x, int DigitsAfterDecimal) { std::ostringstream FormatStream;
FormatStream << "%0." << DigitsAfterDecimal;
boost::format Formatter(FormatStream.str());
Formatter % x;
return Formatter.str(); }
Have you looked at boost spirit's karma lib? IIRC, it outperforms most other libs with formatted output like this. Jeff
Chris, greetings --
Chris Stankevitz
Question 1: Is there an efficient way to do the following (and by "more efficient" I mean fewer format constructors and string parsing):
void WriteLog(float x, float y, float z, const Employee& e) { std::cout << "Values: " << boost::format("%0.3") % x << e << boost::format("%0.3") % y << boost::format("%0.3") % z; }
Please take a look at the benchmarks mentioned in the boost.format documentation: http://www.boost.org/doc/libs/1_52_0/libs/format/doc/format.html#performance They're a few years out of date, but they cover the most straight- forward way to get the power of boost.format without quite as much parsing / constructing overhead: make one const instance, then copy construct to create your mutable instances. Assuming the copy constructor is thread-safe (which, if you're not using internal state like str() does, then it should be -- but no guarantees...) then something like this: // single copy to do work of parsing static const boost::format fixed3proto( "%0.3f" ); // now clone it for each format operation boost::format fixed3( fixed3proto ); // and use the cloned copy fixed3 % x; return fixed3.str(); In this situation, where you have three floats that you want formatted a particular way, then using maniuplators on cout is reasonable; just make sure you save the state (with ios_base_all_saver or friend). But be aware that some of those manipulators will still be in force when you try to emit the Employee object...
Question 2: Is there a more efficient way to do this:
std::string FloatToString(float x, int DigitsAfterDecimal) { std::ostringstream FormatStream; FormatStream << "%0." << DigitsAfterDecimal; boost::format Formatter(FormatStream.str()); Formatter % x; return Formatter.str(); }
In this particular case, since you're already building an ostringstream, you can just use the standard manipulators: std::ostringstream oss; oss << std::fixed << std::setprecision( DigitsAfterDecimal ) << x; return oss.str(); Note that ostringstream construction isn't entirely lightweight; if you have an easy way of keeping an instance around in a thread-safe manner, then you might be better off having a single instance per thread, then doing: oss.str( "" ); oss << std::fixed << std::setprecision( DigitsAfterDecimal ) << x; return oss.str(); (Further, if that's the only thing you ever use that ostringstream for, you can possibly shave a few more cycles off by using the flags field directly; I don't recall if fixed and setprecision last past a single value output.) However, if you really do require the fastest formatting, you're probably best off calling into the old C library with snprintf -- but you are then responsible for sizing your buffer correctly, etc. Happy hacking, t.
participants (5)
-
Anthony Foiani
-
Chris Stankevitz
-
Jeff Flinn
-
Krzysztof Czainski
-
Steve Lorimer