I was recently looking at some (rather old) code that was relying on std::ostringstream in a large, performance senstive loop. (Yes, I know using iostreams in performance sensitive code is a bad idea, but legacy code exists.)
The code was using a common pattern to reset a ostringstream instance each time through the loop to avoid having to construct a new instance every time.
std::ostringstream oss;
for(const MyType & value : values)
{
oss << value;
doSomethingWithString(oss.str());
// Assign an empty string to the internal buffer. This should reset
// the size to zero, but keep the allocated buffer. In older code,
// you often see this written as oss.str("").
oss.str({});
oss.clear(); // Reset the stream
}
When migrating the code to C++20, I was excited to use the new std::ostringstream::view() getter to skip an unnecessary copy of the std::string out of the stream's internal buffer.
std::ostringstream oss;
for(const MyType & value : values)
{
oss << value;
doSomethingWithStringView(oss.view());
oss.str({});
oss.clear();
}
Then I noticed that the std::ostringstream::str setter gained an r-value reference overload in C++20. That would let us pre-allocate our string buffer just once. Nice!
std::ostringstream oss;
{
std::string buffer;
buffer.reserve(1024);
oss.str(std::move(buffer));
}
for(const MyType & value : values)
{
oss << value;
doSomethingWithStringView(oss.view());
oss.str({});
oss.clear();
}
But wait. That means that the oss.str({}) call inside the loop is doing the exact same thing. So it's wiping out our allocation every time through the loop! Uh oh.
It seems that to clear the internal buffer while keeping its allocation, one must now explicitly call the const reference overload of str().
const std::string empty;
std::ostringstream oss;
{
std::string buffer;
buffer.reserve(1024);
oss.str(std::move(buffer));
}
for(const MyType & value : values)
{
oss << value;
doSomethingWithStringView(oss.view());
oss.str(empty);
oss.clear();
}
So if your codebase uses std::ostringstream, you might want to do a quick grep for str("") and str({}) to see if the upgrade to C++20 silently caused you to start throwing away your stream buffers over and over again.