【问题标题】:Why no front() method on std::map (and other associative containers from the STL)?为什么 std::map (以及 STL 中的其他关联容器)上没有 front() 方法?
【发布时间】:2013-06-03 14:42:48
【问题描述】:

STL reference 似乎在概念上有所不同:

  • 一方面是“序列容器”(数组向量双端队列 forward_list 列表)
  • 另一方面,“关联容器”(设置多集映射 multimap unordered_set unordered_multiset unordered_map unordered_multimap)。

另外,我们好像有:

  • 所有实现begin() 方法的容器返回一个指向容器中第一个元素的迭代器。
  • 只有具有front() 方法的序列容器返回对容器中第一个元素的引用。

我的理解是 front() 方法可以很容易地定义为 begin() 方法,只需取消引用它的返回值。

因此,我的问题是:为什么没有为定义begin() 方法的所有对象定义front() 方法?(实际上应该是每个容器)

(我想从语义的角度来看,从地图中获取第一个元素并没有从向量中获取第一个元素那么有意义,但我想知道是否有更有效的解释)。

【问题讨论】:

  • 我能想到的最好的答案是,接口经常被指定为“鼓励什么使用”,以及“什么可以高效实现”。非序列容器仍然可以迭代(因此它们需要有begin()end(),但它们并不是真正适用于您只需要从中选择第一个元素的情况。所以它们没有@ 987654331@,即使它可以实现
  • 好吧,这就是我当时所期待的。谢谢大家的回答。此外,为每个容器定义的方法没有任何区别会更容易(如“减少重复代码的数量”)吗?
  • @wolfgang 我不了解你,但我更倾向于遵循 Herb Sutter、Bjarne Stroustrup 以及大多数其他 C++ 大师和标准化委员会成员使用的术语,而不是 SO不受控制的强迫症只是不得不溢出并试图在不存在的地方制造混乱的用户。人们说“STL”时的意思非常非常清楚。它们的意思是“基于 actual STL 库的 C++ 标准库的子集”。你可以让 Scott Meyers 将他的书重命名为“Effective STL”的那一天就是我停止使用这个名字的那一天
  • @jalf 一个简单的“我不同意”就足够了,因此更具建设性和主题性还不够吗?

标签: c++ dictionary stl iterator container-data-type


【解决方案1】:

你是对的,它可以很容易地实现。但问题是这些容器是为特定用途而设计的。拥有front() 成员意味着容器的目标 是有一个明确的顺序。当然map 值是有序的,但这更多的是性能问题。当然,任何内部结构都必须从某个地方开始(提供begin()),但有时提供front()back()是没有意义的。

迭代器用于遍历数据,front() 成员用于访问明确排序的集合的第一个元素。访问地图的第一个成员没有意义,因为它是关联的。

【讨论】:

    【解决方案2】:

    我推测:

    • front()back() 不会存在于 Sequence 中,如果不是因为接口最初设计时考虑了 可变 序列。当您考虑如何将push_front()pop_front() 结合使用时,front() 最有意义。对于不可变序列(其中新出现的array 是标准中的唯一示例,除非您算上const vector),front()*begin() 的简写,根本不值得兴奋。

    • 由于无序容器没有push_front(),因此也不值得给它们front()。您可以将条目添加到map,但您无法指定添加它们的顺序,因为这是密钥的用途。这是序列与有序集合之间的区别。

    • “等等”,你说,“vectorfront() 但没有push_front()”。我怀疑这是因为vectorback()——如果你使用back(),那么再次使用front() 来匹配它是“不错的”。

    不过,这只是推测,基于我对设计有用/令人满意的 API 的了解,以及我对容器 API 的观察。我不知道 Stepanov 对此事的想法,也不知道在标准委员会中讨论的任何记录。

    【讨论】:

      【解决方案3】:

      Front() 表示排序; “行中的第一个”。

      Begin() 意味着让我们从某个地方开始,无论在哪里。

      【讨论】:

      • 但地图中有排序
      • 他们的排序很弱。理论上两个或更多条目可能在前面。在某些情况下,所有条目都应该放在前面。
      • Internally, the elements in a map are always sorted by its key following a specific strict weak ordering criterion indicated by its internal comparison object (of type Compare). 但正如 Eddie 所说,地图是树,所以 front() 没有多大意义......
      • @Enigma 不,地图总是只有一个元素在前面(好吧,除非它是空的)
      • 正是因为这个原因,我期待 std::map::front/back 退出。迭代地图并不常见,在循环内部你很清楚这是第一个和最后一个元素,但在外面你不知道:(
      【解决方案4】:

      STL 旨在使用迭代器进行遍历。 所以我猜front() 只对listdeque 这样的容器有意义。

      【讨论】:

      • 但是 所有 STL 容器可以使用迭代器进行遍历。甚至unordered_map
      • 没错。这就是我想说的。
      【解决方案5】:

      您确实必须向标准委员会询问该问题 (comp.lang.c++.std),但我的猜测是,是的,它只是没有多大意义。此外,它的含义还没有那么清楚。你要root,先预购,先后购,先插入……?序列很清楚:前面是一侧,后面是另一侧。地图就是树。

      【讨论】:

      • 就我个人而言,我认为front() 是否存在应该表示哪个条目完全清晰。这意味着begin() 所指的那个,与序列相同。地图有一个顺序,你需要有一个“第一个元素”就是一个顺序并且不能为空。 API 几乎隐藏了它们是树的事实。您不能在预购、后购或插入订单中迭代 std::map,因此您也不应该期望 front() 与这些事情有任何关系。
      • “所有你需要有一个“第一个元素”是一个订单并且不能是空的”我突然想到从数学上讲这是我的咆哮。无限集可以有顺序但没有最少元素。不用说,std::map 是有限的。
      • 可能是因为map中的first和last不稳定。没有push_front,因为这对于平衡二叉树来说是胡言乱语,可能出于同样的原因front 被省略或者因为他们觉得两者结合在一起。
      猜你喜欢
      • 2015-11-26
      • 2011-03-24
      • 2010-10-15
      • 1970-01-01
      • 1970-01-01
      • 2019-11-06
      • 1970-01-01
      • 2014-06-20
      • 2011-01-13
      相关资源
      最近更新 更多