Использование streambuf при отправке / получении структуры
Я работаю на boost::asio::streambuf
и обнаружил, что я могу отправить / получить структуру, используя ее, но когда я отправляю структуру, я просто не могу получить ее, как отправил. Документация говорит, что нужно использовать commit()
а также consume()
, но где мне их здесь использовать?
struct person
{
int m_id;
std::string m_message;
};
std::istream& operator>>(std::istream& in, struct person& p)
{
return in >> p.m_id >> p.m_message;
}
std::ostream& operator<<(std::ostream& out, struct person& p)
{
return out << p.m_id << " " << p.m_message;
}
int main()
{
boost::asio::streambuf buf;
std::ostream out(&buf);
person p;
p.m_id = 1;
p.m_message = "Hello World!";
out << p;
std::istream in(&buf);
person p1;
in >> p1;
cout << "ID: " << p1.m_id << endl;
cout << "Message: " << p1.m_message << endl;
return 0;
}
Проблема со строками, поэтому, когда я набираю только "привет" (без мира), он работает нормально, но если я добавлю "мир!" как показано выше, он просто не видит добавленный "мир!", почему?
2 ответа
Есть ряд вопросов.
Во-первых, приведите аргументы
const&
когда возможно:std::ostream &operator<<(std::ostream &out, person const &p) {
Во-вторых, убедитесь, что потоки сбрасываются в буфер. Я думаю, что хорошей практикой является ограничение срока службы
ostream
или жеistream
экземплярыВ-третьих, выберите формат, который будет надежным. Ваш образец уже имел большие проблемы, когда вы имели
m_id = 1
а такжеm_message = "123"
(видишь?).В текстовых форматах вам нужны либо поля фиксированной длины, либо протокол разграничения. Давайте исправим это:
std::ostream &operator<<(std::ostream &out, person const &p) { return out << p.m_id << ";" << p.m_message.length() << ";" << p.m_message; }
Теперь, читая его, вы увидите, насколько точнее вы должны быть:
std::istream &operator>>(std::istream &in, person &p) { char separator; size_t length; bool ok = in >> p.m_id && in >> separator && separator == ';' && in >> length && in >> separator && separator == ';' ; if (ok) { p.m_message.resize(length); in.read(&p.m_message[0], length); p.m_message.resize(in.gcount()); } // ensure the expected number of bytes were read ok = ok && (p.m_message.length() == length); if (!ok) in.setstate(std::ios::failbit); return in; }
Хлоп. В самом деле? Да, действительно. Минимум!
Обработка ошибок
Полная демонстрация
#include <boost/asio.hpp>
#include <iostream>
struct person {
int m_id;
std::string m_message;
};
std::ostream &operator<<(std::ostream &out, person const &p) {
return out << p.m_id << ";" << p.m_message.length() << ";" << p.m_message;
}
std::istream &operator>>(std::istream &in, person &p) {
char separator;
size_t length;
bool ok = in >> p.m_id
&& in >> separator && separator == ';'
&& in >> length
&& in >> separator && separator == ';'
;
if (ok) {
p.m_message.resize(length);
in.read(&p.m_message[0], length);
p.m_message.resize(in.gcount());
}
// ensure the expected number of bytes were read
ok = ok && (p.m_message.length() == length);
if (!ok)
in.setstate(std::ios::failbit);
return in;
}
int main() {
boost::asio::streambuf buf;
std::ostream(&buf) << person{ 1, "Hello World!" };
person received;
if (std::istream(&buf) >> received) {
std::cout << "ID: " << received.m_id << std::endl;
std::cout << "Message: " << received.m_message << std::endl;
} else {
std::cout << "Couldn't receive person\n";
}
}
Печать
ID: 1
Message: Hello World!
БОНУС
C++14 добавлено std::quoted
:
#include <iomanip>
std::ostream &operator<<(std::ostream &out, person const &p) { return out << p.m_id << std::quoted(p.m_message); }
std::istream &operator>>(std::istream &in, person &p) { return in >> p.m_id >> std::quoted(p.m_message); }
Который, в этом случае, также делает работу: Live On Coliru
С http://en.cppreference.com/w/cpp/string/basic_string/operator_ltltgtgt (выделение и многоточие):
2)... читает символы из is и добавляет их в str..., пока не выполнится одно из следующих условий:
- ...
- ...
- std:: isspace (c, is.getloc ()) имеет значение true для следующего символа c в is (этот пробельный символ остается во входном потоке)....
В основном это означает, что если вы извлекаете строку из istream
с помощью operator >>
это останавливается в белых пространствах.
Если вы хотите получить все из потока в вашу строку, есть множество вопросов, задающих это (как этот или этот).