Использование 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 ответа

Решение

Есть ряд вопросов.

  1. Во-первых, приведите аргументы const& когда возможно:

    std::ostream &operator<<(std::ostream &out, person const &p) {
    
  2. Во-вторых, убедитесь, что потоки сбрасываются в буфер. Я думаю, что хорошей практикой является ограничение срока службы ostream или же istream экземпляры

  3. В-третьих, выберите формат, который будет надежным. Ваш образец уже имел большие проблемы, когда вы имели 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;
    }
    

    Хлоп. В самом деле? Да, действительно. Минимум!

  4. Обработка ошибок

Полная демонстрация

Жить на Колиру

#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 >> это останавливается в белых пространствах.

Если вы хотите получить все из потока в вашу строку, есть множество вопросов, задающих это (как этот или этот).

Другие вопросы по тегам