【问题标题】:Using streambuf when sending/getting struct发送/获取结构时使用streambuf
【发布时间】:2018-05-03 22:35:45
【问题描述】:

我正在处理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;
}

问题在于字符串,所以当我只输入“hello”(没有世界)时,它工作正常,但如果我添加“世界!”如上所示,只是没有看到添加的“世界!”,为什么?

【问题讨论】:

    标签: c++ boost-asio streambuf


    【解决方案1】:

    有很多问题。

    1. 首先,尽可能使用const&amp; 的参数:

      std::ostream &operator<<(std::ostream &out, person const &p) {
      
    2. 其次,确保流刷新到缓冲区。我认为限制ostreamistream 实例的生命周期是一个好习惯

    3. 第三,选择稳健的格式。当你有m_id = 1m_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. 进行错误处理

    完整演示

    Live On Coliru

    #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

    【讨论】:

    • 作为奖励添加了a C++14 version based on std::quoted(被低估的功能)
    • 这确实是一个更详尽的答案,+1
    • 当person的struct包含charshortintstd::string时,operator&gt;&gt;会返回fail?
    • @LiuGuangxuan 我不确定你的意思。这有帮助吗? coliru.stacked-crooked.com/a/87feed568c394db4
    • @sehe 是的,我就是这个意思。我想知道为什么charshort 这样的类型是固定大小的,还需要分隔符吗?
    【解决方案2】:

    来自http://en.cppreference.com/w/cpp/string/basic_string/operator_ltltgtgt(强调和省略号是我的):

    2) ... 从 is 读取字符并将它们附加到 str ... 直到一个 以下条件中的一个为真:

    • ...
    • ...
    • std::isspace(c,is.getloc()) 为真对于下一个字符 c in is(此空白字符保留在输入流中)。 ...

    这基本上意味着,如果您使用operator &gt;&gt;istream 中提取字符串,它将在空格处停止。

    如果您想从流中获取所有内容到您的字符串中,有很多问题会问这个问题(例如 this onethis one)。

    【讨论】:

    • 虽然有帮助,但它并不能完全解决这种格式的问题,IYAM
    猜你喜欢
    • 2013-03-09
    • 2017-11-12
    • 2019-08-05
    • 2013-01-07
    • 2011-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多