2016-12-08 47 views
8
#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(); 
} 

Jak przenieść ukryty obiekt łańcucha std :: ostringstream?Jak przenieść ukryty obiekt łańcucha std :: ostringstream?

+2

Myślę, że można to zrobić przez 's = ruch (oss.rdbuf() -> Str())' [Och, sprawdziłem, ** nie można **], ale ryzykujesz złamanie założeń kodu strumienia przez wyciągnięcie dywanu spod jego stóp. *. Dlaczego tego chcesz? –

+1

Myślę, że możesz wymyślić coś interesującego za pomocą 'uchwyt węzła' z C++ 17: http://en.cppreference.com/w/cpp/container/node_handle – alexeykuzmin0

+4

To nie jest możliwe, nie ma obowiązku, że' std :: basic_stringbuf' używa 'std :: basic_string' jako bazowego bufora (mimo, że tak to robi się w praktyce). – user657267

Odpowiedz

3

Standard mówi, że std::ostringstream::str() returns a copy.

Jednym ze sposobów uniknięcia tej kopii jest zaimplementowanie innej klasy pochodnej std::streambuf, która bezpośrednio ujawnia bufor ciągu. Boost.IOStreams czyni to dość banalne:

#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'; 
} 
+2

Ten * także kopiuje * ciąg znaków, ponieważ '' buffer-> string'' nie jest ani wartością prynkową, ani tymczasową, ani nie spełnia wymagań dotyczących kopiowania, ponieważ jest to nazwa nieulotnego obiektu automatycznego czasu przechowywania (i tego samego typu, co zwrócone). W tym przypadku * masz * wymusić ruch za pomocą np. '' std :: move''. Ponieważ '' buffer-> string'' w żadnym wypadku nie może kwalifikować się do kopiowania, nie wyklucza to innych optymalizacji. –

+0

@ArneVogel Masz rację, że istnieje tutaj inna operacja kopiowania. Zaktualizowano. –