问题 Boost.Intrusive和unordered_map


我希望使用侵入式unordered_map。由于某种原因,库中只有一个unordered_set。还有一个侵入式哈希表,但我不确定它是否具有相同的功能,也没有相同的界面。
我错了,我错过了unordered_map链接?
如果我不是有一个教程,将帮助我实现一个?


4822
2017-07-31 15:50


起源



答案:


这是一个有趣的问题。 Boost.Intrusive似乎没有提供任何有序或无序的地图接口。它有很多实现类型可以正常工作,因为它们都是有序的(红黑树,AVL树,splay树)和无序(hashtables)的映射。但没有地图,我无法告诉你原因。

我看到你有两个选择:

  1. 只是用 hashtable:无序容器实现为哈希表(并且它们不是唯一的原因)   hash_map 是为了避免与已经使用该名称的预先存在的库发生名称冲突。如果你想完成你的工作,这将有效。
  2. 如果你真的想要实现自己的,你想看看Boost.Intrusive的接口描述 unordered_set。我没有看过实现,但它几乎可以肯定是一个或多个树类型的包装器。 std::set 和 std::map 通常都是作为红黑树周围的包装器实现的(在我看过的所有标准库实现中:GCC,MSVC和Apache的stdcxx)。另请参考libstdc ++如何包装其树实现 <map> 并在 <set>。这是很多样板文件,其中大部分内容繁琐但两种类型都将几乎所有的工作推迟到树上。类似的东西几乎肯定会发生在Boost.Intrusive上 unordered_set。您需要查看map和set接口之间的差异,并将其用作修改的基础 unordered_set 成 unordered_map

我做了后者。这有点单调乏味,我强烈建议为它编写单元测试(或者窃取libstdc ++或Boost.Intrusive附带的单元测试)。但这是可行的。我还强烈建议您在SGI阅读集合和地图的需求文档(地图)或为 的libstdc ++

更新: 我意识到他们没有做地图的原因:侵入式容器要求您将数据结构的节点信息嵌入到您存储在其中的值类型中。对于地图,您必须为这两个值执行此操作 和钥匙。这不是不可能的,而是标准的实现 map 使用 相同 内部类型为 set做。但那些内部类型只有   value_type 变量:存储键和值,它们将键和值复制到该变量中并将其存储在节点中。要使用侵入式类型(即不进行复制),您必须将该实现类型修改为与集不兼容:它必须存储对键和值的引用 分别。所以要做到这一点,你还必须修改你使用的实现(可能 hashtable)。同样不是不可能,但图书馆设计师可能会试图避免严重的代码重复,因此在没有简单的方法实现这一点的情况下,他们很可能决定将地图留下。

那有意义吗?


7
2017-07-31 17:24



那不值得麻烦吗?因为我在这里考虑时间与质量。 - the_drow
这是相当多的工作。标准容器的接口有很多细微之处。我同样假设侵入式容器。如果时间紧迫,请选择1.如果您有时间并且想要真正学到很多,请选择选项2。 - quark
你说你自己做了。你介意分享吗? - the_drow
我错过了一些明显的东西吗当然你可以将密钥存储在它们放在值类型中的钩子中,它只是钩子的另一部分......恕我直言,侵入式容器的主要优点是它们避免了节点的分配和释放,复制密钥进入节点似乎很好......当然,我 需要 一张地图,这是一种痛苦,他们已经做了各种各样聪明的套装,根本没有地图! - Len Holgate


答案:


这是一个有趣的问题。 Boost.Intrusive似乎没有提供任何有序或无序的地图接口。它有很多实现类型可以正常工作,因为它们都是有序的(红黑树,AVL树,splay树)和无序(hashtables)的映射。但没有地图,我无法告诉你原因。

我看到你有两个选择:

  1. 只是用 hashtable:无序容器实现为哈希表(并且它们不是唯一的原因)   hash_map 是为了避免与已经使用该名称的预先存在的库发生名称冲突。如果你想完成你的工作,这将有效。
  2. 如果你真的想要实现自己的,你想看看Boost.Intrusive的接口描述 unordered_set。我没有看过实现,但它几乎可以肯定是一个或多个树类型的包装器。 std::set 和 std::map 通常都是作为红黑树周围的包装器实现的(在我看过的所有标准库实现中:GCC,MSVC和Apache的stdcxx)。另请参考libstdc ++如何包装其树实现 <map> 并在 <set>。这是很多样板文件,其中大部分内容繁琐但两种类型都将几乎所有的工作推迟到树上。类似的东西几乎肯定会发生在Boost.Intrusive上 unordered_set。您需要查看map和set接口之间的差异,并将其用作修改的基础 unordered_set 成 unordered_map

我做了后者。这有点单调乏味,我强烈建议为它编写单元测试(或者窃取libstdc ++或Boost.Intrusive附带的单元测试)。但这是可行的。我还强烈建议您在SGI阅读集合和地图的需求文档(地图)或为 的libstdc ++

更新: 我意识到他们没有做地图的原因:侵入式容器要求您将数据结构的节点信息嵌入到您存储在其中的值类型中。对于地图,您必须为这两个值执行此操作 和钥匙。这不是不可能的,而是标准的实现 map 使用 相同 内部类型为 set做。但那些内部类型只有   value_type 变量:存储键和值,它们将键和值复制到该变量中并将其存储在节点中。要使用侵入式类型(即不进行复制),您必须将该实现类型修改为与集不兼容:它必须存储对键和值的引用 分别。所以要做到这一点,你还必须修改你使用的实现(可能 hashtable)。同样不是不可能,但图书馆设计师可能会试图避免严重的代码重复,因此在没有简单的方法实现这一点的情况下,他们很可能决定将地图留下。

那有意义吗?


7
2017-07-31 17:24



那不值得麻烦吗?因为我在这里考虑时间与质量。 - the_drow
这是相当多的工作。标准容器的接口有很多细微之处。我同样假设侵入式容器。如果时间紧迫,请选择1.如果您有时间并且想要真正学到很多,请选择选项2。 - quark
你说你自己做了。你介意分享吗? - the_drow
我错过了一些明显的东西吗当然你可以将密钥存储在它们放在值类型中的钩子中,它只是钩子的另一部分......恕我直言,侵入式容器的主要优点是它们避免了节点的分配和释放,复制密钥进入节点似乎很好......当然,我 需要 一张地图,这是一种痛苦,他们已经做了各种各样聪明的套装,根本没有地图! - Len Holgate


自问这个问题已经很久了,但我认为来这里的人应该对如何使用这个问题感兴趣 unordered_set 作为地图。解决方案是使用 高级插入方法:只需将密钥及其值存储在同一个密钥中 value_type,并使用它插入 insert_check 和 insert_commit


6
2017-07-26 12:44



从技术上讲,您甚至不需要高级插入,只需要高级查找(查找(键))。 - John Zwinck