Copie el contenido de un streambuf a una cadena

Aparentemente boost::asio::async_read no le gustan las cadenas, ya que la única sobrecarga de boost::asio::buffer me permite crear const_buffer s, así que estoy atascado con leer todo en un streambuf.
Ahora quiero copiar el contenido del streambuf en una cadena, pero aparentemente solo admite escribir en char * ( sgetn() ), crear un istream con streambuf y usar getline() .

¿Hay alguna otra manera de crear una cadena con los contenidos del streambufs sin una copia excesiva?

No sé si cuenta como ” copia excesiva “, pero puede usar un stringstream:

 std::ostringstream ss; ss << someStreamBuf; std::string s = ss.str(); 

Como, para leer todo, desde stdin en una cadena, hacer

 std::ostringstream ss; ss << std::cin.rdbuf(); std::string s = ss.str(); 

Alternativamente, también puede usar un istreambuf_iterator . Tendrás que medir si esta o la forma anterior es más rápida, no lo sé.

 std::string s((istreambuf_iterator(someStreamBuf)), istreambuf_iterator()); 

Tenga en cuenta que someStreamBuf anterior pretende representar un streambuf* , así que tome su dirección según corresponda. También tenga en cuenta los paréntesis adicionales alrededor del primer argumento en el último ejemplo, para que no lo interprete como una statement de función que devuelve una cadena y toma un iterador y otro puntero a la función ("análisis más molesto").

Está realmente enterrado en los documentos …

Given boost::asio::streambuf b , con size_t buf_size

 boost::asio::streambuf::const_buffers_type bufs = b.data(); std::string str(boost::asio::buffers_begin(bufs), boost::asio::buffers_begin(bufs) + buf_size); 

Otra posibilidad con boost::asio::streambuf es usar boost::asio::buffer_cast() junto con boost::asio::streambuf::data() y boost::asio::streambuf::consume() esta manera:

 const char* header=boost::asio::buffer_cast(readbuffer.data()); //Do stuff with header, maybe construct a std::string with std::string(header,header+length) readbuffer.consume(length); 

Esto no funcionará con streambufs normales y podría considerarse sucio, pero parece ser la forma más rápida de hacerlo.

Para boost::asio::streambuf , puede encontrar una solución como esta:

  boost::asio::streambuf buf; /*put data into buf*/ std::istream is(&buf); std::string line; std::getline(is, line); 

Imprime la cadena:

  std::cout << line << std::endl; 

Puede encontrarlo aquí: http://www.boost.org/doc/libs/1_49_0/doc/html/boost_asio/reference/async_read_until/overload3.html

También se pueden obtener los caracteres de asio::streambuf usando std::basic_streambuf::sgetn :

 asio::streambuf in; // ... char cbuf[in.size()+1]; int rc = in.sgetn (cbuf, sizeof cbuf); cbuf[rc] = 0; std::string str (cbuf, rc); 

La razón por la que solo puede crear const_buffer desde std :: string es porque std :: string explícitamente no admite la escritura directa basada en punteros en su contrato. Podrías hacer algo malvado como cambiar el tamaño de la cuerda a un cierto tamaño, luego const_cast la constness de c_str () y tratarla como un búfer crudo * char, pero eso es muy malo y te meterá en problemas algún día.

Yo uso std :: vector para mis buffers porque mientras el vector no cambie de tamaño (o tengas cuidado de lidiar con el cambio de tamaño), puedes escribir directamente el puntero. Si necesito algunos de los datos como std :: string, tengo que copiarlos, pero por la forma en que trato con mis búferes de lectura, cualquier cosa que necesite durar más allá de la callback debe ser copiada independientemente.

Una respuesta más simple sería convertirlo en std::string y manipularlo de alguna manera como esta

  std::string buffer_to_string(const boost::asio::streambuf &buffer) { using boost::asio::buffers_begin; auto bufs = buffer.data(); std::string result(buffers_begin(bufs), buffers_begin(bufs) + buffer.size()); return result; } 

Dando un código muy conciso para la tarea.

Creo que es más como:

 streambuf.commit( number_of_bytes_read ); istream istr( &streambuf ); string s; istr >> s; 

No he basic_streambuf código basic_streambuf , pero creo que debería ser solo una copia en la cadena.

Probé la primera respuesta y obtuve un error de comstackción al comstackr usando “g ++ -std = c ++ 11” Lo que funcionó para mí fue:

  #include  #include  #include  //other code ... boost::asio::streambuf response; //more code std::ostringstream sline; sline << &response; //need '&' or you a compiler error std::string line = sline.str(); 

Esto comstackdo y funcionado.