如何移动std :: ostringstream的底层字符串对象?

xml*_*lmx 8 c++ performance rvalue-reference move-semantics c++11

#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();
}
Run Code Online (Sandbox Code Playgroud)

如何移动std :: ostringstream的底层字符串对象?

Max*_*kin 3

标准说std::ostringstream::str()返回一个副本

避免这种复制的一种方法是实现另一个std::streambuf直接公开字符串缓冲区的派生类。Boost.IOStreams 使这变得非常简单:

#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';
}
Run Code Online (Sandbox Code Playgroud)

  • 这也*复制*字符串,因为``buffer-&gt;string``既不是纯右值,也不是临时值,也不满足复制省略作为自动存储持续时间的非易失性对象的名称的要求(并且与返回的类型相同)。在这种情况下,您*必须*使用例如“std::move”来强制移动。由于“buffer-&gt;string”在任何情况下都不可能符合复制省略的条件,因此这不会阻止其他优化。 (2认同)