Как получить часть std::string в streambuf без копирования?
В последнее время я часто использую Boost Asio и обнаруживаю, что работаю с std::string
с и asio::streambuf
довольно много. Я нахожу, что я пытаюсь получить данные назад и вперед между streambuf
с и string
Это как разбор сетевых данных. В общем, я не хочу возиться с "отформатированным IO", поэтому iostream
не очень полезны Я нашел это в то время как ostream::operator<<()
, несмотря на официальную документацию, похоже, передает string
с в streambuf
безмятежный, istream::operator>>()
калечат содержимое моего streambuf
s (как и следовало ожидать, учитывая, что он "отформатирован").
Мне действительно кажется, что в стандартной библиотеке отсутствует множество итераторов и потоковых объектов для работы с streambuf
с и string
и неформатный ио. Например, если я хочу получить подстроку string
в streambuf
Как мне это сделать, не создавая копию string
? Базовая универсальная передача может быть выполнена следующим образом:
// Get a whole string into a streambuf, and then get the whole streambuf back
// into another string
{
boost::asio::streambuf sbuf;
iostream os(&sbuf);
string message("abcdefghijk lmnopqrs tuvwxyz");
cout << "message=" << message << endl;
os << message;
std::istreambuf_iterator<char> sbit(&sbuf);
std::istreambuf_iterator<char> end;
std::string sbuf_it_wholestr(sbit, end);
cout << "sbuf_it_wholestr=" << sbuf_it_wholestr << endl;
}
печатает:
message=abcdefghijk lmnopqrs tuvwxyz
sbuf_it_wholestr=abcdefghijk lmnopqrs tuvwxyz
Если я хочу получить только часть streambuf
в строку, которая кажется очень сложной, потому что istreambuf_iterator
не является итератором с произвольным доступом и не поддерживает арифметику:
// Get a whole string into a streambuf, and then get part of the streambuf back
// into another string. We can't do this because istreambuf_iterator isn't a
// random access iterator!
{
boost::asio::streambuf sbuf;
iostream os(&sbuf);
string message("abcdefghijk lmnopqrs tuvwxyz");
cout << "message=" << message << endl;
os << message;
std::istreambuf_iterator<char> sbit(&sbuf);
// This doesn't work
//std::istreambuf_iterator<char> end = sbit + 7; // Not random access!
//std::string sbuf_it_partstr(sbit, end);
//cout << "sbuf_it_partstr=" << sbuf_it_partstr << endl;
}
И, кажется, нет никакого способа прямого использования string::iterator
s, чтобы сбросить часть string
в streambuf
:
// istreambuf_iterator doesn't work in std::copy either
{
boost::asio::streambuf sbuf;
iostream os(&sbuf);
string message("abcdefghijk lmnopqrs tuvwxyz");
cout << "message=" << message << endl;
std::istreambuf_iterator<char> sbit(&sbuf);
//std::copy(message.begin(), message.begin()+7, sbit); // Doesn't work here
}
Я всегда могу вытащить частичное string
из вне streambuf
если я не против форматированного io, но я делаю - форматированный io почти никогда не является тем, что я хочу:
// Get a whole string into a streambuf, and then pull it out using an ostream
// using formatted output
{
boost::asio::streambuf sbuf;
iostream os(&sbuf);
string message("abcdefghijk lmnopqrs tuvwxyz");
cout << "message=" << message << endl;
string part1, part2;
os << message;
os >> part1;
os >> part2;
cout << "part1=" << part1 << endl;
cout << "part2=" << part2 << endl;
}
печатает:
message=abcdefghijk lmnopqrs tuvwxyz
part1=abcdefghijk
part2=lmnopqrs
Если я в порядке с некрасивой копией, я могу, конечно, сгенерировать подстроку - std::string::iterator
это произвольный доступ...
// Get a partial string into a streambuf, and then pull it out using an
// istreambuf_iterator
{
boost::asio::streambuf sbuf;
iostream os(&sbuf);
string message("abcdefghijk lmnopqrs tuvwxyz");
cout << "message=" << message << endl;
string part_message(message.begin(), message.begin()+7);
os << part_message;
cout << "part_message=" << part_message << endl;
std::istreambuf_iterator<char> sbit(&sbuf);
std::istreambuf_iterator<char> end;
std::string sbuf_it_wholestr(sbit, end);
cout << "sbuf_it_wholestr=" << sbuf_it_wholestr << endl;
}
печатает:
message=abcdefghijk lmnopqrs tuvwxyz
part_message=abcdefg
sbuf_it_wholestr=abcdefg
У stdlib также есть как ни странно std::getline()
что позволяет вытащить отдельные линии из ostream
:
// If getting lines at a time was what I wanted, that can be accomplished too...
{
boost::asio::streambuf sbuf;
iostream os(&sbuf);
string message("abcdefghijk lmnopqrs tuvwxyz\n1234 5678\n");
cout << "message=" << message << endl;
os << message;
string line1, line2;
std::getline(os, line1);
std::getline(os, line2);
cout << "line1=" << line1 << endl;
cout << "line2=" << line2 << endl;
}
печатает: message=abcdefghijk lmnopqrs tuvwxyz 1234 5678
line1=abcdefghijk lmnopqrs tuvwxyz
line2=1234 5678
Я чувствую, что есть какой-то Розеттский камень, который я пропустил и который имеет дело с std::string
а также asio::streambuf
было бы намного проще, если бы я обнаружил это. Следует просто отказаться от std::streambuf
интерфейс и использовать asio::mutable_buffer
из которого я могу выбраться asio::streambuf::prepare()
?
2 ответа
istream::operator>>() меняет содержимое моих streambufs (как и следовало ожидать, учитывая, что он "отформатирован").
Откройте ваш входной поток с
std::ios::binary
помечать и манипулировать имis >> std::noskipws
Например, если я хочу получить подстроку строки в streambuf, как мне это сделать, не создавая копию строки? Базовый общий перевод может быть выполнен как
Попробуй как
outstream.write(s.begin()+start, length);
Или использовать
boost::string_ref
:outstream << boost::string_ref(s).instr(start, length);
И, похоже, нет прямого способа использовать string:: iterators для выгрузки части строки в streambuf:
std::copy(it1, it2, ostreambuf_iterator<char>(os));
Число рейнольдса парсинг строк сообщения:
Вы можете разделить диапазоны итераторов с помощью
iter_split
,Вы можете разобрать встроенную грамматику на лету с
boost::spirit::istream_iterator
Если я ничего не упустил, вам просто нужноstd::streambuf::sputn()
my_buf.sputn(mystr.data(), mystr.size());