Update: In the face of people's continued dislike of this answer, I thought I'd make an edit and explain.
No, there is no way to avoid a string copy (stringbuf has the same interface)
It will never matter. It's actually more efficient that way. (I will try to explain this)
Imagine writing a version of stringbuf
that keeps a perfect, moveable std::string
available at all times. (I have actually tried this).
Adding characters is easy - we simply use push_back
on the underlying string.
OK, but what about removing characters (reading from the buffer)? We'll have to move some pointer to account for the characters we've removed, all well and good.
However, we have a problem - the contract we're keeping that says we'll always have a std::string
available.
So whenever we remove characters from the stream, we'll need to erase
them from the underlying string. That means shuffling all the remaining characters down (memmove
/memcpy
). Because this contract must be kept every time the flow of control leaves our private implementation, this in practice means having to erase characters from the string every time we call getc
or gets
on the string buffer. This translates to a call to erase on every <<
operation on the stream.
Then of course there's the problem of implementing the pushback buffer. If you pushback characters into the underlying string, you've got to insert
them at position 0 - shuffling the entire buffer up.
The long and short of it is that you can write an ostream-only stream buffer purely for building a std::string
. You'll still need to deal with all the reallocations as the underlying buffer grows, so in the end you get to save exactly one string copy. So perhaps we go from 4 string copies (and calls to malloc/free) to 3, or 3 to 2.
You'll also need to deal with the problem that the streambuf interface is not split into istreambuf
and ostreambuf
. This means you still have to offer the input interface and either throw exceptions or assert if someone uses it. This amounts to lying to users - we've failed to implement an expected interface.
For this tiny improvement in performance, we must pay the cost of:
developing a (quite complex, when you factor in locale management) software component.
suffering the loss of flexibility of having a streambuf which only supports output operations.
Laying landmines for future developers to step on.
return
value. There is noreturn
here. – Dochandorrachistringstream
anywhere here. – Dochandorrachmove(ss).str()
, but I don't know if any does right now. – Moxiestr()
if there will be more writes or not. – Flabbergastss.rdbuf()
which is supposed not to create the intermediate string. – Mcguire.str()
. About the Standard quote, its a "copy" in an abstract sense since a string is a different media than a stream. But the implementation could do whatever it likes. Being practical, whoever cares of how that implementation works, if the data of the stream is buffered and can be easily moved into the stream instead of copied, etc... – Bearskinstring &
that would just use this as the underlying buffer. – Dodecanese