将类数据存储在随机访问文件中的最佳实践

Posted

技术标签:

【中文标题】将类数据存储在随机访问文件中的最佳实践【英文标题】:Best practice in storing class data in random access files 【发布时间】:2015-10-25 14:23:18 【问题描述】:

在 C 中,数据通常以struct 数据类型组织。这保存在随机访问文件中非常方便,因为您可以在结构上使用sizeof 直接跳到您想要的记录。

我不清楚在 C++ 中执行此操作的最佳方法是什么,其中您有一个包含数据的类(以及一些当然不需​​要持久化的成员函数)。直接存储类似乎是错误的,因为这当然会包括指向函数的指针以及那些一旦被持久化到文件就是垃圾的东西。

我能想到的另一种方法是将类中需要持久化的成员数据更改为struct,并更改访问器函数以查看内部数据结构。它似乎有点过于交织,但似乎是避免重复每个字段两次的唯一合乎逻辑的方法(一次在单独的struct 中,一次在课堂上)。

这当然会在您拥有继承的那一刻崩溃,并且派生类会添加新字段。尽管这几乎不是 C++ 和随机访问文件特有的问题,而且它在许多其他对象持久性方法(包括其他编程语言中流行的 ORM 包)中面临different possible strategies even when saving to a database table for instance。

人们通常在 C++ 中使用任何“事实上的标准”方法来将类数据保存在文件中吗?无需在所有地方复制东西?

【问题讨论】:

不,目前还没有针对 c++ 的序列化标准。不过有一些非常常用的库,例如 boost::archive 或 google 协议缓冲区。 谢谢。我不是在寻找这样的标准。如果您有一个包含一些数据的类并且您需要将其保存到文件中(并且以后能够查找它),人们通常会做什么。人们只是复制一切吗? 好吧,如果你真的需要随机访问,即使我提到的那些库实际上也不合适。您最可能需要的是数据库存储。 我不太了解您问题中的某些部分:类成员函数通常是无状态的,因此不必持久化。您只需要存储对象数据,与 C 结构相同。 顺便说一句,只是将纯 c 结构写入文件,也可能有同样的问题,如指针字段、字节序问题等。 【参考方案1】:

简短回答:视情况而定

中等答案:它取决于 C 中的结构是否可以直接序列化。

长答案:如果一个类 A 只是普通旧数据,它将像使用 C 结构一样可序列化,即二进制副本并加载 sizeof(A) 字节。如果一个类只包含原始类型成员或它们的数组,和/或本身就是 POD 的子对象,那么它就是一个 POD 对象。它可以有方法或静态方法,但没有虚拟方法(甚至没有虚拟析构函数)。

例如 char 数组是可以接受的,但没有指针、没有字符串、没有引用,并且(一般来说)没有来自标准库的对象(特别是没有 std::string)。

当然,由于它直接存储和加载二进制数据表示,它肯定不能跨不同架构移植,但可以用于本地保存状态。

【讨论】:

谢谢。那么在现实中,如果是POD对象,成员函数就不会被持久化? @jbx:非虚成员函数不存储在对象本身中,因此它们的指针不会被持久化。【参考方案2】:

在 C++ 中,structclass 之间的唯一区别是它们的默认可见性; struct 默认为公开,class 默认为私有。您可以通过struct 完成的任何操作都可以通过class 完成。两者都可以有构造函数、析构函数、成员函数、基类型、虚拟成员等。

只要一个类型是可简单复制的(即,该类型有一个普通的析构函数、复制构造函数、移动构造函数、复制赋值运算符和移动赋值运算符),或者如果您使用 C++98 则为 POD 类型,那么它可以像在 C 中一样被序列化为文件。请注意,任何具有虚拟成员的类型,或从具有虚拟成员的类型继承(虚拟或其他方式)的任何类型都不可轻易复制。

编辑:非虚成员函数不影响类型的布局。对象本身没有存储指向此类函数的指针。

【讨论】:

如果类有成员函数会发生什么?指向这些成员函数的指针不会也被持久化(因此我会节省垃圾)? 我添加了一些关于成员函数如何影响对象布局的说明。查看我的编辑。【参考方案3】:

如果所有成员函数都是无状态的(成员函数中没有定义静态局部变量),C++ 类和 C 风格的结构没有区别:您只需序列化每个类实例的成员数据。

为了进一步澄清,当您编写序列化程序(或更常用的序列化库)时,您永远不会存储 vtable,因为没有意义:只有成员数据特定于对象实例,而 vtable 是定义的由班级。 因此,拥有虚函数的唯一真正影响是您不再处理 POD 对象:您不能简单地将整个结构内存转储到磁盘上,并且必须一个接一个地序列化类实例

【讨论】:

这仍然会给您带来不同 CPU 架构之间的可移植性问题。 @DanielStrul 我认为您误解了这个问题。如果一个类有成员函数,我不想保留它们的指针或类似的垃圾。持久化整个对象将包括它。放置一个内部 struct 而不是成员变量,并保留 struct,可以避免这种情况。我只是想问人们是否还有其他“典型”方法。

以上是关于将类数据存储在随机访问文件中的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

在安全区域中存储内容的最佳实践

华为云CDN加速OBS桶文件最佳实践

MySQL中存储UUID的最佳实践

在数据库中存储动态字段时的最佳实践

在 iOS 中保存访问令牌的最佳实践

磁盘数据库存储,最佳实践