为了账号安全,请及时绑定邮箱和手机立即绑定

如何在C+中序列化对象?

如何在C+中序列化对象?

C++
青春有我 2019-07-13 10:43:00
我有一个小的对象层次结构,我需要通过套接字连接来序列化和传输这些对象。我需要同时序列化对象,然后根据对象的类型反序列化它。在C+中是否有一种简单的方法(就像在Java中那样)?是否有任何C+序列化联机代码示例或教程?编辑:为了明确起见,我正在寻找将对象转换为字节数组的方法,然后再将其转换为对象。我能处理插座传输。
查看完整描述

3 回答

?
婷婷同学_

TA贡献1844条经验 获得超8个赞

在某些情况下,在处理简单类型时,可以:

object o;socket.write(&o, sizeof(o));

这可以作为概念的证明或初稿,这样你的团队中的其他成员就可以继续在其他部分工作。

但迟早通常更早这会让你受伤的!

你会遇到以下问题:

  • 虚拟指针表将被破坏。
  • 指针(指向数据/成员/函数)将被破坏。
  • 不同机器上填充/对齐的差异。
  • 大/小字节排序问题。
  • 浮动/双倍实现的变化。

(另外,你需要知道在接收方你要打开什么。)

您可以通过为每个类开发自己的编组/解编组方法来改进这一点。(理想情况下是虚拟的,因此可以在子类中扩展它们。)一些简单的宏将允许您以大/小-端中性的顺序相当快地写出不同的基本类型。

但这种粗制滥造的工作要好得多,而且更容易,通过Boost序列化库.


查看完整回答
反对 回复 2019-07-13
?
慕码人2483693

TA贡献1860条经验 获得超9个赞

序列化意味着将对象转换为二进制数据。反序列化意味着从数据重新创建对象。

序列化时,您将字节推入uint8_t矢量。取消序列化时,您将从uint8_t矢量。

当然,在序列化东西时可以使用一些模式。

每个可序列化的类都应该有一个serialize(std::vector<uint8_t> &binaryData)或类似的签名函数,将其二进制表示写入所提供的向量。然后,这个函数可以将这个向量传递给它的成员的序列化函数,这样他们也可以将它们的内容写入其中。

因为数据表示在不同的体系结构上可能是不同的。您需要找出如何表示数据的方案。

让我们从基础开始:

序列化整数数据

只需按小Endian顺序写字节即可。如果尺寸重要,也可以使用varint表示。

按小端点顺序序列化:

data.push_back(integer32 & 0xFF);data.push_back((integer32 >> 8) & 0xFF);data.push_back((integer32 >> 16) & 0xFF);data.push_back((integer32 >> 24) & 0xFF);

从小端序反序列化:

integer32 = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);

序列化浮点数据

据我所知,IEEE 754在这里拥有垄断地位。我不知道有什么主流建筑会用别的东西来做浮标。唯一不同的是字节顺序。一些体系结构使用小Endian,另一些使用大Endian字节顺序。这意味着您需要小心哪种顺序大声地向您发出接收端的字节。另一个不同之处是处理非正态值、无穷大值和NaN值。但是,只要你避免这些值,你就应该没事。

序列化:

uint8_t mem[8];memcpy(mem, doubleValue, 8);data.push_back(mem[0]);data.push_back(mem[1]);...

反序列化是向后执行。注意架构的字节顺序!

序列化字符串

首先,您需要就编码达成一致。乌特夫-8是很常见的。然后以长度前缀的方式存储它:首先使用我前面提到的方法存储字符串的长度,然后逐字节编写字符串。

序列化数组。

它们和字符串是一样的。首先序列化表示数组大小的整数,然后序列化数组中的每个对象。

序列化整个对象

就像我之前说的,他们应该有一个serialize方法,该方法向量添加内容。要取消对象的序列化,它应该有一个接受字节流的构造函数。它可以是istream但在最简单的情况下,它只是一个参考uint8_t指针。构造函数从流中读取它想要的字节,并在对象中设置字段。如果系统设计良好并按对象字段顺序序列化字段,则只需将流传递给初始化程序列表中的字段构造函数,并按正确的顺序反序列化。

序列化对象图

首先,您需要确保这些对象是否确实是要序列化的对象。如果目标上存在这些对象的实例,则不需要序列化它们。

现在,您发现需要序列化指针所指向的对象。指针仅在使用它们的程序中有效的问题。不能序列化指针,应停止在对象中使用指针。相反,创建对象池。这个对象池基本上是一个包含“方框”的动态数组。这些框有参考计数。非零引用计数表示活动对象,零表示空槽.然后创建与Shared_PTR类似的智能指针,该指针不存储指向对象的指针,而是存储在数组中的索引。您还需要就表示空指针的索引达成一致,例如。-1。

基本上,我们在这里所做的是用数组索引替换指针。现在,当序列化时,您可以像往常一样序列化这个数组索引。您不需要担心对象在目标系统的内存中的位置。确保他们也有相同的对象池。

所以我们需要序列化对象池。但是哪一个呢?那么,当您序列化对象图时,您并不只是序列化一个对象,而是序列化整个系统。这意味着系统的序列化不应该从系统的各个部分开始。这些对象不应该担心系统的其他部分,它们只需要序列化数组索引,仅此而已。您应该有一个系统序列化程序例程,该例程负责编排系统的序列化,并遍历相关的对象池并序列化所有对象池。

在接收端,所有对象中的数组都被反序列化,重新创建所需的对象图。

序列化函数指针

不要在对象中存储指针。有一个静态数组,其中包含指向这些函数的指针,并将索引存储在对象中。

因为这两个程序都将这个表编译到了书架上,所以只使用索引就可以了。

序列化多态类型

由于我说过您应该避免序列化类型中的指针,并且应该使用数组索引,所以多态不能工作,因为它需要指针。

您需要使用类型标记和联合来解决这个问题。

版本化

最重要的是。您可能需要不同版本的软件互操作。

在这种情况下,每个对象都应该在序列化开始时写入版本号,以指示版本。

当在另一边加载对象时,较新的对象可能能够处理旧的表示,但旧的对象不能处理新的表示,因此它们应该抛出一个异常。

每当某件事情发生变化时,您都应该增加版本号。


因此,要总结这一点,序列化可能很复杂。但幸运的是,您不需要序列化程序中的所有内容,大多数情况下,只有协议消息被序列化,这通常是普通的旧结构。所以你不需要我经常提到的复杂技巧。


查看完整回答
反对 回复 2019-07-13
  • 3 回答
  • 0 关注
  • 361 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信