Search code examples
c++performancec++11move-semanticsrvalue-reference

How to move std::ostringstream's underlying string object?


#include <sstream>
#include <string>

using namespace std;

template<typename T>
string ToString(const T& obj)
{
    ostringstream oss;
    oss << obj;

    //
    // oss will never be used again, so I should
    // MOVE its underlying string.
    //
    // However, below will COPY, rather than MOVE, 
    // oss' underlying string object!
    //
    return oss.str();
}

How to move std::ostringstream's underlying string object?


Solution

  • The standard says that std::ostringstream::str() returns a copy.

    One way to avoid this copy is to implement another std::streambuf derived-class that exposes the string buffer directly. Boost.IOStreams makes this pretty trivial:

    #include <boost/iostreams/stream_buffer.hpp>
    #include <iostream>
    #include <string>
    
    namespace io = boost::iostreams;
    
    struct StringSink
    {
        std::string string;
    
        using char_type = char;
        using category = io::sink_tag;
    
        std::streamsize write(char const* s, std::streamsize n) {
            string.append(s, n);
            return n;
        }
    };
    
    template<typename T>
    std::string ToString(T const& obj) {
        io::stream_buffer<StringSink> buffer{{}};
    
        std::ostream stream(&buffer);
        stream << obj;
        stream.flush();
    
        return std::move(buffer->string); // <--- Access the string buffer directly here and move it.
    }
    
    int main() {
        std::cout << ToString(3.14) << '\n';
    }