【问题标题】:How is end() implemented in STL containers?end() 在 STL 容器中是如何实现的?
【发布时间】:2011-04-18 03:23:19
【问题描述】:

所以当我们需要从头到尾遍历一个容器时,我们会写类似

for (i = v->begin(); i != v->end(); i++)

假设i 是容器v 的迭代器。

我的问题是“什么保证 end 总是指向容器中最后一个元素之后的元素?” STL 是如何确保这种行为的,这种情况有没有可能是不正确的?

【问题讨论】:

  • STL 不保证这种行为。 STL 根据标准定义的要求实现此行为。标准说这就是它应该如何工作实现 STL 的开发人员然后应该使 STL 正常工作。
  • 这不是最佳做法。当您不存储值时,首选预增量运算符 ++i 而不是 i++。对于许多类型,它更快。
  • @Jive Dadson:这不是我主要关心的问题 --> 在循环的每一轮重新计算 v->end() 肯定效率较低...for (auto it = v.begin(), end = v.end(); it != end; ++it) 是规范形式,尽管在 C++ 中0x 还不如使用for (auto val : v)std::foreach 和一个lambda 函数。

标签: c++ stl


【解决方案1】:

STL 通过始终存储如下内容来确保这种行为:

最后(双关语),end() 是什么并不重要,只要它始终是end()(而且,显然,可以'不要与任何其他节点混淆)。

【讨论】:

  • 伙计,你会因为时髦的图形而获得 +1 :-)
  • C++ 标准中的以下引用不是使这个答案无效吗?尤其是图形。
【解决方案2】:

C++03 Section 23.1/7

begin() 返回一个引用容器中第一个元素的迭代器。

end() 返回一个迭代器,它是容器的 past-the-end 值。

如果容器是空的,那么begin() == end();

【讨论】:

  • 这是 slist 不是官方 STL 的原因吗? slist 的 end() 为 0
【解决方案3】:

stl 规范保证 end 将超过 end See here。情况将永远如此。具体如何做到这一点取决于实现(例如,有时值只是设置为 null),但请放心,只要 v 是有效指针,您的循环就可以了。

【讨论】:

    【解决方案4】:

    “end 将始终指向容器中最后一个元素之后的一个”意味着如果增加指向最后一个元素的迭代器,它将等于end() 的结果。实施可以不同。在 Visual C++ 中,std::vector::end() 返回包含零指针的特定于实现的迭代器。

    【讨论】:

    • 我强烈怀疑它,因为std::vector<T>::iterator 是一个随机访问迭代器。如果std::vector<T>::end()返回(T*)0end()-begin()是非法的,但需要返回std::vector::size()
    • 更正确地说:end 返回包含零指针的特定于实现的迭代器。
    • 保持零指针的部分是不需要且不精确的。在gcc向量实现中,vector<>::end()定义为vector<>::begin()+vector<>::size(),实际上存储在vector<>对象中(GCC向量通过三个指针实现:beginend 和 end_of_capacity,其中 begin==end 如果向量为空,begin+size()==end 始终和 end==end_of_capacity 如果 size()==capacity()。没有 零指针随处可见。
    • @David Rodríguez,那是在“实施可以不同”中。我回答的一部分。 “零指针”与 Visual C++ 实现有关,与 gcc 无关。
    【解决方案5】:

    您是在询问所有 STL 容器...没有提及向量,特别是在哪里 end() 可能 如您显然直观地期望的那样实现。 std::map 的结尾是什么? “结束是最后使用的节点之后的一个”只是一个逻辑概念,表示您可以安全地从该最后使用的节点递增,将其与“结束”的抽象概念区分/等同,并做一些节点算术,其中 end 被认为比最后使用的节点更远。不要太从字面上理解。

    【讨论】:

      【解决方案6】:

      正如之前的一些海报所说,end() 是一个结束元素。如果您需要通过迭代器访问最后一个元素,请使用 iter = container.end() - 1; 否则,对于向量,variable = someVector.back(); 假设该变量的数据类型为 someVector 包含。

      关于它指向终点的保证,容器本身会在内部处理它。您只需像对待任何其他对象一样将其视为黑匣子,并相信它会正确执行。

      每当调整容器大小时,它都会跟踪结束的位置,并且在您再次访问end() 之前保持最新状态。但是,根据容器的不同,如果您有一个迭代器并以某种方式对其进行更改,它可能会使迭代器无效并破坏您的迭代过程。

      【讨论】:

        猜你喜欢
        • 2023-03-27
        • 1970-01-01
        • 2023-03-09
        • 2020-10-13
        • 2018-11-06
        • 2019-10-12
        • 1970-01-01
        • 2011-02-26
        • 2012-04-03
        相关资源
        最近更新 更多