Скопируйте содержимое потокового буфера в строку
-
22-08-2019 - |
Вопрос
Видимо boost::asio::async_read
не любит строки, так как единственная перегрузка boost::asio::buffer
позволяет мне создавать const_buffer
s, поэтому я застрял в чтении всего в стримбуф.
Теперь я хочу скопировать содержимоеstreambuf в строку, но он, видимо, поддерживает только запись в char* (sgetn()
), создав istream с помощьюstreambuf и используя getline()
.
Есть ли другой способ создать строку с содержимым потокового буфера без чрезмерного копирования?
Решение
Я не знаю, считается ли это "чрезмерное копирование", но вы можете использовать строковый поток:
std::ostringstream ss;
ss << someStreamBuf;
std::string s = ss.str();
Например, чтобы прочитать все из стандартного ввода в строку, выполните
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*
, поэтому примите его адрес соответствующим образом.Также обратите внимание на дополнительные круглые скобки вокруг первого аргумента в последнем примере, чтобы он не интерпретировался как объявление функции, возвращающей строку и принимающей итератор и другой указатель на функцию («самый неприятный анализ»).
Другие советы
Его Действительно похороненный в документах...
Данный 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);
Другая возможность с 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);
Это не будет работать с обычными потоковыми буферами и может считаться грязным, но, похоже, это самый быстрый способ сделать это.
Для boost::asio::streambuf
вы можете найти такое решение:
boost::asio::streambuf buf;
/*put data into buf*/
std::istream is(&buf);
std::string line;
std::getline(is, line);
Распечатайте строку:
std::cout << line << std::endl;
Вы можете найти здесь: http://www.boost.org/doc/libs/1_49_0/doc/html/boost_asio/reference/async_read_until/overload3.html
Также можно получить персонажей из 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);
Причина, по которой вы можете создать const_buffer только из std::string, заключается в том, что std::string явно не поддерживает прямую запись на основе указателей в своем контракте.Вы могли бы сделать что-нибудь злое, например изменить размер строки до определенного размера, затем const_cast константу из c_str() и обращаться с ней как с необработанным буфером char*, но это очень нехорошо и когда-нибудь доставит вам проблемы.
Я использую std::vector для своих буферов, потому что до тех пор, пока размер вектора не изменяется (или вы внимательно относитесь к изменению размера), вы можете прекрасно выполнять прямую запись указателя.Если мне нужны некоторые данные в виде std::string, мне придется скопировать их, но из-за того, как я работаю с буферами чтения, все, что должно продолжаться после обратного вызова чтения, должно быть скопировано в любом случае.
Более простым ответом было бы преобразовать его в 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;
}
Даю очень краткий код для задачи.
Я думаю, это больше похоже на:
streambuf.commit( number_of_bytes_read );
istream istr( &streambuf );
string s;
istr >> s;
Я не заглядывал в basic_streambuf
код, но я считаю, что это должна быть только одна копия в строке.
Я проверил первый ответ и получил ошибку компилятора при составлении «g ++ -Std = c ++ 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();
Это скомпилировалось и запустилось.