是否有可能编写真正通用的磁盘烘焙B + Tree实现?

时间:2010-11-25 21:16:03

标签: c++ object-persistence subtree

我几次用C ++编写了一个通用的内存中B + Tree实现,我正在考虑让它在磁盘上持久化(这就是为什么B + Tree最初设计的原因)。 我的第一个想法是使用mmap(我在Linux下)能够将文件作为普通内存操作,只需重写我的节点类的 new 运算符,以便它返回映射部分中的指针并创建一个智能指针,可以将RAM地址转换为文件偏移量,以便将我的节点与其他节点链接起来。 但我希望我的实现是通用的,因此用户可以在B +树中存储int,std :: string或他想要的任何自定义类。 这就是问题发生的地方:对于不包含指针的原始类型或聚合类型都是好的,但只要对象包含指向堆分配对象的指针/引用,这种方法就不再有效。

所以我的问题是:是否有一些已知的方法来克服这个困难?我对该主题的个人搜索最终没有成功,但也许我错过了一些东西。

3 个答案:

答案 0 :(得分:4)

据我所知,有三种(有点)简单的方法可以解决这个问题。

方法1 :写一个std::streambuf指向一些预先分配的内存。

这种方法允许您使用operator<<并使用现有的任何代码来获取您想要的字符串表示。

  • Pro:重复使用现有代码。
  • Con:无法控制operator<<如何吐出内容。
  • Con:仅基于文本的表示。

方法2 :编写自己的(多次重载)输出函数。

  • Pro:可以提出二进制表示法。
  • Pro:对每种输出格式的精确控制。
  • Con:重写这么多的输出函数...客户端为新类型写入重载是一件痛苦的事情,因为它们不应该编写属于库命名空间的函数...除非你求助于Koenig(依赖于参数)查找!

方法3 :撰写btree_traits<>模板。

  • Pro:可以提出二进制表示法。
  • Pro:对每种输出格式的精确控制。
  • Pro:更多控制输出和格式的功能,可能包含元数据和所有。
  • Con:仍需要您/您图书馆的用户编写大量自定义重载。
  • 专业:除非有人超越这些特质,否则btree_traits<>请求使用operator<<

答案 1 :(得分:0)

你不能写一个真正通用和透明的版本,因为如果一个非平凡的项目中的指针被分配了malloc(或new和new []),那么它已经在堆中了。

非透明溶胶可能是序列化类是一种选择,这可以相对容易地完成。在存储类之前,您必须调用序列化函数,然后在调用它之前调用反序列化函数。 Boost具有良好的序列化功能,您可以使用B + Tree。

答案 2 :(得分:0)

以通用方式处理指针和引用意味着您需要检查您要存储的结构的类型及其字段。 C ++是一门以其反思而闻名的语言。

但即使在具有强大反思的语言中,这个问题的通用解决方案也很困难。您可能能够使用它来处理更高级语言(如Python,Ruby等)中的子集类型。相关且更强大的范例是persistent programming language

您想要的功能通常是通过将编写数据块的责任委派给目标类型本身来实现的。它被称为serialization。它只是意味着使用转储数据的方法编写接口,以及加载数据的方法。任何想要保存在B树中的类只需实现此接口。