Boost序列化二进制存档给出错误的输出

Boost Serialization Binary Archive giving incorrect output

本文关键字:出错 错误 输出 序列化 二进制 Boost      更新时间:2023-10-16

我正在尝试序列化一个类。

类别定义:

class StartPeerSessionRequest {
public:
    StartPeerSessionRequest();
    virtual ~StartPeerSessionRequest();
    void composeRequestwithHardCodeValues();
    void save();
    stringstream serializedRequest;
    /*boost::serialization::binary_object serlreq;*/
private:
    StartPeerSessionRequest(const StartPeerSessionRequest &);
    uint16_t mProtocolVersion;
    uint16_t mSessionFlags;
    uint16_t mMaxResponseLength;
    string   mMake;
    string   mModel;
    string   mSerialNumber;
    uint8_t  mTrackDelay;
    string   mHeadUnitModel;
    string   mCarModelYear;
    string   mVin;
    uint16_t mVehicleMileage;
    uint8_t  mShoutFormat;
    uint8_t  mNotificationInterval;
    friend class boost::serialization::access;
    template <typename Archive> void serialize(Archive &ar, const unsigned int version);
};
StartPeerSessionRequest::StartPeerSessionRequest() {
    mProtocolVersion      = 1 * 10000 + 14 * 100 + 4;
    mSessionFlags         = 1;
    mMaxResponseLength    = 0;
    mMake                 = "MyMake";
    mModel                = "MyModel";
    mSerialNumber         = "10000";
    mTrackDelay           = 0;
    mHeadUnitModel        = "Headunit";
    mCarModelYear         = "2014";
    mVin                  = "1234567980";
    mVehicleMileage       = 1000;
    mShoutFormat          = 3;
    mNotificationInterval = 1;
}
template <class Archive> void StartPeerSessionRequest::serialize(Archive &ar, const unsigned int version) {
    ar & mProtocolVersion;
    ar & mSessionFlags;
    ar & mMaxResponseLength;
    ar & mMake;
    ar & mModel;
    ar & mSerialNumber;
    ar & mTrackDelay;
    ar & mHeadUnitModel;
    ar & mCarModelYear;
    ar & mVin;
    ar & mVehicleMileage;
    ar & mShoutFormat;
    ar & mNotificationInterval;
}
void StartPeerSessionRequest::save() {
    boost::archive::binary_oarchive oa(serlreq, boost::archive::no_header);
    oa << (*this);
    /*cout<<"n binary_oarchive :"<<serlreq.size();*/
    boost::archive::text_oarchive ota(serializedRequest, boost::archive::no_header);
    ota << (*this);
    cout << "n text_oarchive :" << serializedRequest.str() << "size :" << serializedRequest.str().size();
}

serializedRequest.str.size()为我提供了87 的长度

实际上它应该为我提供65个字节。(我已经数过了,你可以从构造函数中计算出来)

我怀疑它在两者之间增加了长度。

我试过使用text_archive,但它也不起作用。

我需要的只是简单地序列化类成员

我想我需要使用一些特征或包装。

请让我知道

感谢

好吧,为了看看我会怎么做,我试着达到我在餐巾纸背面计算的最佳尺寸:

我可以看到你对57、63或75字节的期望

mProtocolVersion      = 1*10000+14*100+4; // 2 bytes
mSessionFlags         = 1;                // 2 bytes
mMaxResponseLength    = 0;                // 2 bytes
mMake                 = "MyMake";         // 6 bytes + length
mModel                = "MyModel";        // 7 bytes + length
mSerialNumber         = "10000";          // 5 bytes + length
mTrackDelay           = 0;                // 1 byte
mHeadUnitModel        = "Headunit";       // 8 bytes + length
mCarModelYear         = "2014";           // 4 bytes + length
mVin                  = "1234567980";     // 10 bytes + length
mVehicleMileage       = 1000;             // 2 byte
mShoutFormat          = 3;                // 1 byte
mNotificationInterval = 1;                // 1 byte
// -------------------------------------- // 51 bytes + 6 x length

在这个例子中,我使用Boost Spirit创建了二进制序列化代码(Karma用于序列化,Qi用于反序列化)。我使长度字段的大小可配置(8,16,32或64位无符号)。

这是一个有效的概念验证:在Coliru上直播

generate()

constgenerate成员函数将工作委托给单独命名空间中的辅助函数:

template <typename Container>
bool generate(Container& bytes) const {
    auto out = std::back_inserter(bytes);
    using my_serialization_helpers::do_generate;
    return do_generate(out, mProtocolVersion)
        && do_generate(out, mSessionFlags)
        && do_generate(out, mMaxResponseLength)
        && do_generate(out, mMake)
        && do_generate(out, mModel)
        && do_generate(out, mSerialNumber)
        && do_generate(out, mTrackDelay)
        && do_generate(out, mHeadUnitModel)
        && do_generate(out, mCarModelYear)
        && do_generate(out, mVin)
        && do_generate(out, mVehicleMileage)
        && do_generate(out, mShoutFormat)
        && do_generate(out, mNotificationInterval);
}

注意

  • do_generate过载可以根据未来类型的需要自由添加
  • 容器可以容易地从例如std::vector<unsigned char>切换到例如boost::interprocess::containers::string<char, char_traits<char>, boost::interprocess::allocator<char, boost::interprocess::managed_shared_memory::segment_manager> >

parse()

parse方法非常相似,只是它委托do_parse重载来完成工作。

测试

测试程序使用所有可能的配置进行往返:

  • 8位长度字段,净57字节,具有boost序列化:70
  • 16位长度字段,净63字节,具有boost序列化:76
  • 32位长度字段,net 75字节,具有boost序列化:88
  • 64位长度字段,净99字节,具有boost序列化:112

正如您所看到的,自然Boost Serialization解决方案在我的系统上占用107个字节(只比我上次的配置多了8个字节),这甚至还不算太离谱。

还要注意的是,由于Karma生成器都采用任何输出迭代器,因此为了提高性能和避免分配中间存储,将其直接连接到低级Boost Archive操作应该相对容易。

对于Boost Serialization应该如何序列化为其专有的、不可移植的二进制格式,您似乎有一些非常具体的假设。

Boost序列化更高级,或多或少是专门为处理非POD数据而设计的。如果您坚持,您应该能够直接序列化POD类型的数组。然而,在您的问题中,该类根本不是POD,因此无论如何都不能按位序列化。

有关可移植档案,请参阅EOS可移植档案。

Boost Archives有可选的标志来抑制格式头:

enum archive_flags {
    no_header = 1,          // suppress archive header info
    no_codecvt = 2,         // suppress alteration of codecvt facet
    no_xml_tag_checking = 4 // suppress checking of xml tags - igored on saving
};

请参阅归档模型

这里有一个背景,看看是什么引入了简单的按位序列化的开销:

  • 提升C++序列化开销
  • 如何使用自定义库的boost库进行性能测试
相关文章: