Скопируйте содержимое streambuf в строку

По-видимому, boost::asio::async_read не любит строки, так как единственная перегрузка boost::asio::buffer позволяет мне создавать const_buffer s, поэтому я застрял в чтении всего в streambuf.
Теперь я хочу скопировать содержимое streambuf в строку, но, по-видимому, поддерживает только запись в char * (sgetn()), создавая istream с streambuf и используя getline().

Есть ли другой способ создать строку с содержимым streambufs без чрезмерного копирования?

Ответы

Ответ 1

Я не знаю, считается ли это "чрезмерным копированием", но вы можете использовать stringstream:

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

Как, чтобы читать все, начиная с stdin в строку, do

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

В качестве альтернативы вы также можете использовать istreambuf_iterator. Вам придется измерять, быстрее ли это или выше, - я не знаю.

std::string s((istreambuf_iterator<char>(someStreamBuf)), 
               istreambuf_iterator<char>());

Обратите внимание, что someStreamBuf выше предназначено для представления streambuf*, поэтому, при необходимости, введите его адрес. Также обратите внимание на дополнительные круглые скобки вокруг первого аргумента в последнем примере, так что он не интерпретирует его как объявление функции, возвращающего строку, и принимает итератор и другой указатель на функцию ( "самый неприятный синтаксический анализ" ).

Ответ 2

Он действительно похоронен в документах...

Учитывая boost:: asio:: streambuf b, с 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);

Ответ 3

Другой возможностью с boost::asio::streambuf является использование boost::asio::buffer_cast<const char*>() в сочетании с boost::asio::streambuf::data() и boost::asio::streambuf::consume() следующим образом:

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

Это не будет работать с обычными streambufs и может считаться грязным, но, похоже, это самый быстрый способ сделать это.

Ответ 5

Можно также получить символы из asio::streambuf с помощью 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);

Ответ 6

Причина, по которой вы можете создавать const_buffer только из std::string, состоит в том, что std::string явно не поддерживает прямую запись в указателе в своем контракте. Вы можете сделать что-то злое, как изменить размер строки до определенного размера, а затем const_cast constness из c_str() и обработать ее как сырой буфер char *, но это очень непослушный и вызовет у вас проблемы когда-нибудь.

Я использую std::vector для своих буферов, потому что, пока вектор не изменяет размер (или вы осторожны, чтобы иметь дело с изменением размера), вы можете просто писать прямой указатель. Если мне нужны некоторые данные в качестве std::string, я должен его скопировать, но так, как я общаюсь с моими буферами для чтения, все, что должно длиться за пределами обратного вызова чтения, должно быть скопировано независимо.

Ответ 7

Я проверил первый ответ и получил ошибку компилятора при компиляции с использованием "g++ -std = С++ 11" Что для меня работало:

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

Скомпилировано и запущено.

Ответ 8

Простым ответом было бы преобразовать его в std::string и манипулировать им каким-то таким, как этот

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

Предоставление очень сжатого кода для задачи.

Ответ 9

Я думаю, что это больше похоже:


streambuf.commit( number_of_bytes_read );

istream istr( &streambuf );
string s;
istr >> s;

Я не смотрел код basic_streambuf, но считаю, что это должна быть только одна копия в строку.