【问题标题】:Is it possible to have an unordered_map with non-const key type?是否可以有一个非 const 键类型的 unordered_map?
【发布时间】:2013-01-30 18:07:13
【问题描述】:

基本上,我想要一个容器,其中一个元素可以通过多个键访问。这可以通过定义一些多键类用作映射的键​​类型来完成,但由于这种解决方案不允许修改已插入元素的键,因此我无法为现有条目。

我很欣赏std::map 的键需要保持不变才能进行排序,但为什么std::unordered_map 会存在此限制?

如果需要,我想我可以使用指针映射,但有没有更好、更优雅的解决方案?

编辑:谢谢你清理 Andrei,Xeo。 Nicol,关于我应该使用什么容器有什么建议吗?

【问题讨论】:

  • 限制不是为了排序,而是为了保证键的唯一性。
  • 因为最终通过比较器模板参数检查元素是否等效,默认情况下为std::equal_to<K>
  • 如果你需要这个,那么你需要一个新的容器。
  • 不太明白什么是“无法为现有条目创建新别名”。或许可以举个例子说明你想做什么?
  • 好吧,如果您可以任意更改键的值,unordered_map 将需要感知每一个更改(因此必须在键的某种代理对象上工作,无论如何) 以重组自身,这反过来又会使该元素的任何迭代器无效。键决定了一个元素在数据结构中的位置,所以修改它只会带来麻烦。而且这甚至都没有说通过改变它来破坏键的唯一性。

标签: c++ stl c++11 unordered-map stdmap


【解决方案1】:

嗯,std::unordered_map 不允许您修改密钥的原因与其他关联容器不允许您修改它的原因几乎相同:它会破坏该数据结构的内部组织。

unordered_map 中,密钥用于获取散列,该散列告诉容器将元素放置在哪个桶中(当然还有从哪个桶中检索它)。如果您修改密钥,则修改哈希,这意味着您的元素应该移动到不同的存储桶。基本上,这就像删除它并重新插入它一样。

另一方面,关联容器的整体理念是,任何元素都由一个固定值表示,因此可以根据该值快速计算其在容器中的位置。如果允许使用多个键,您会使用哪一个来快速确定元素的存储或存储位置?

您想要的可能是一个 ad-hoc 数据结构,它具有不同于标准库的复杂性保证。

然而,就我个人而言,您似乎只是在寻找引用语义,因为您打算共享一个对象的多个视图。这自然会导致我使用(智能)指针,尤其是当我听到世界“别名”时。我建议你去一张以shared_ptrs 为值的地图。

【讨论】:

  • 它不需要暗示shared_ptrsahred_ptr 的问题在于,一旦使用它,您就可以选择动态分配对象。也许带有视图的主地图也可以(好吧,这会带来其他问题,真的取决于他需要什么)。当然,答案是 +1。
  • @ChristianRau:嗯,从技术上讲,我猜你是对的。另一方面,从实际的角度来看,如果 OP 想要创建别名,他通常不想费心手动保证对象的寿命超过它们的所有引用,因此shared_ptrs 可能会派上用场。跨度>
【解决方案2】:

你会发现引用图比指针图更有品味吗?

int value = 6;

std::unordered_map<int, int&> m;

for(int i=0; i<5; ++i)
    m.emplace(i, value);

value = 4;

for(auto const& i: m)
    std::cout<<i.second<<' ';

当然,您必须将实际值存储在其他地方,如示例所示。

【讨论】:

    【解决方案3】:

    在关联容器中(例如mapunordered_map),key 的值决定了元素在数据结构中的位置。在非多关联容器中,键也必须是唯一的。

    如果允许修改key,那么这将危及上述设计不变量。

    • map中,元素在二叉搜索树中的位置

    • unordered_map 中,将元素链接到哈希桶

    如果我理解 OP 的要求,那么可以通过在容器的 insert() 上编写一个包装器来实现,例如以下 C++ 类伪代码:

    Iterator insert_wrapper( Container & cont, Element const & elem ) {
    
        if elem in cont {
           cont.erase( elem );
        }
    
        return cont.insert( elem );
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-02
      • 1970-01-01
      • 2017-05-06
      • 1970-01-01
      • 2022-11-01
      • 2011-04-29
      相关资源
      最近更新 更多