3

我正在尝试用 C++ 编写一个持久性数据结构,但是我觉得我应该能够使它与我的数据结构阅读器的各种其他实现二进制兼容,因此,我目前的想法是在本机内存中声明数据结构而不进行任何抽象.

例如,我会指定一个线性内存块作为数据结构(使用new关键字),然后描述第一个字节的含义,第二个字节的含义等等。我知道我可以这样做,struct但是随后,数据结构将绑定到一种语言,而其他语言将不得不使用这种结构。此外,实现可能会从编译器更改为编译器。相反,我希望它作为内存标准。

我想做的事情有点明智吗?或者我试图过度简化事情并且真的应该继续使用struct数据结构?现在进入 C++ 部分,如果您认为我应该使用struct数据结构,那么使用成熟的类有什么缺点?

(无论如何,我都在使用一个类来包装内存结构并为其提供函数,因为数据结构无论如何都是持久的。) 编辑 正如贾斯汀所建议的那样,我不需要任何围绕内存结构的高级接口包装器,所以我的最后一点关于类包装器的说明不正确。我的意思是我想要一个用于内存表示的类接口,它不一定是包装器。

4

2 回答 2

1

我已经阅读/使用过的几种文件格式正是这样做的——定义内存标准或布局,然后通常用类似 C 的伪代码演示来支持它struct。有时它们会提供结构或类表示,有些则完全由库抽象。当然,这些格式会继续记录所有字段、它们的大小、数据的字节顺序等。

我认为与字节序相关的问题、填充、复杂性(例如由数据结构的变化引入)和正确的版本控制是最大的错误来源。我发现的另一个问题是过去的数据结构的使用以及用于表示类似功能的数据结构的不一致——你可能会收到一份规范,并意识到它包含几种不同的字符串表示——所有这些都是过时的,有人必须继续支持所有这些(双向)。

继续那条路线:

如果您不想支持二进制表示(或可编译程序)(并且随着平台和工具集的变化,长期存在的格式的尝试在此过程中失败/绊倒),则不应提交它。只需首先提交正式的内存标准,然后在此基础上构建测试和示例输入文件,以验证表示是否正确序列化和反序列化。一个非常基本的测试套件将有助于确保您的模型在您需要的所有系统上都是可移植的,并且可以指出您可能没有意识到的潜在缺陷或特定于平台的注意事项。

如果您真的想提供可编译的表示,我会坚持使用非常兼容的struct表示——客户端可以采用该(在内存中)表示并将其转换为他们喜欢的任何 C++ 抽象/表示。也就是说,序列化的表示可能不应该反映内存中的表示,除了简单的表示和这种表示的中间存储(扁平和打包的结构)。

其中一个重要部分是您应该进行测试,以确认您使用这些结构创建的内存对象图是向前和向后可序列化和可反序列化的,并支持正确的版本控制——因此通常需要做一些工作一个复杂的序列化表示兼容。所以你看到这种方法只是在另一个之上引入了一个抽象层。在这方面,您可能希望 C++ 抽象能够从打包的内存表示中创建自己,并确保该表示也可以正确填充打包结构而不会丢失数据。

除此之外,是否需要更高级的界面?如果有,那么您可能需要提供该信息。

所以是的,内存标准是你必须正确和稳定的部分,所有实现都应该参考和测试——无论平台/架构差异如何。IOW,你走在正确的轨道上;)

于 2012-09-02T02:00:15.890 回答
0

struct在 C++ 中,和之间没有实际区别class(除了默认可访问性是 public in struct)。传统上,struct当一个类型只有(公共)成员变量而没有成员函数时使用,但这只是一个约定,而不是编译器强制执行的规则。

我当然会使用struct/class来描述数据。如果有人想为您的数据结构编写阅读器,他们可以导入您的头文件或以他们选择的语言实现数据结构 - 在大多数编程语言中,这应该非常简单。

我建议你开始你的结构是这样的:

typedef struct
{
    int Version; // struct layout version
    int ByteSize; // byte size of structure for validation
    ...
} MYDATA;

这样,当您的数据结构被传递时,您的代码可以验证分配的结构大小是否与您期望的给定版本的结构的字节数相匹配。然后,您可以通过简单地更新版本字段并检查新大小来轻松引入结构的新版本。

当您将数据保存到磁盘时,请确保将其逐个字段写入,而不是通过单个写入(使用指针并sizeof()确保其他语言不必处理您的 C++ 编译器的潜在填充可能会决定放入。可以在结构中手动布置字段,这样就没有填充,但是在这样做时你必须非常非常小心,而且很容易出错。

于 2012-09-02T01:35:59.487 回答