c++ string boost boost-asio streambuf

c++ - Copie el contenido de un streambuf a una cadena



string boost (9)

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.

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?


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);


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 devolución de llamada debe ser copiada independientemente.


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<char>(someStreamBuf)), istreambuf_iterator<char>());

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 declaración de función que devuelve una cadena y toma un iterador y otro puntero a la función ("análisis más molesto").


Otra posibilidad con boost::asio::streambuf es usar boost::asio::buffer_cast<const char*>() junto con boost::asio::streambuf::data() y boost::asio::streambuf::consume() esta manera:

const char* header=boost::asio::buffer_cast<const char*>(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.



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

#include <string> #include <boost/asio.hpp> #include <sstream> //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 compilado y funcionado.


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);


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.