在不连续的容器中end()以什么方式指向'一个接一个'?

时间:2017-06-26 19:33:45

标签: c++ stl

根据thisthis问题中的答案,C ++标准在第23.2.1节中声明end()对于所有stl容器具有恒定的时间复杂度。

如果我理解正确:

  1. std::forward_list只知道它的第一个元素,每个列表条目只知道下一个元素。
  2. 列表在内存中是非连续的
  3. a.begin() == a.end()适用于空容器a
  4. end()应该是指向'一个超过容器结尾的'的迭代器
  5. 因此,当我在forward_list上进行一些循环时,我想知道:

    在forward_list的情况下,end()如何具有恒定的时间复杂度(即不会前进到“结束之后”)

    我查看了forward_list.cpp并找到了声明

    iterator       end() _NOEXCEPT
        {return       iterator(nullptr);}
    

    这对于恒定的时间要求是有意义的,但不适用于与上述第4点相对应的 - 公认的规则 - 。

    所以仍然存在一些问题:

    • 对于非连续存储而言,“一个接一个”的意思是什么?
    • nullptr如何符合'一个接一个'的定义?
    • 如果MyForwardList.begin() == MyForwardList.end()为空,MyForwardList如何为真?
    • 为什么end()始终未定义为nullptr

4 个答案:

答案 0 :(得分:6)

  

对于非连续存储,one past the end应该是什么意思?

这意味着如果将迭代器增加到最后一个元素,你将得到什么。

  

nullptr如何符合'一个接一个'的定义?

如果你将迭代器增加到最后一个元素,那就是你得到的,那么它符合定义。

  

如果MyForwardList为空,MyForwardList.begin() == MyForwardList.end()如何为真?

对于一个空列表,它们都返回相同的内容。可能是一个“空”的迭代器。

  

为什么end()始终未定义为nullptr

因为有时候这不是定义它的最方便的方法,只要你满足要求,你就可以随意实现它。

它基本上只是一个循环定义。如果你将迭代器带到列表中的最后一个元素并递增它,那么end函数会返回你得到的任何东西,或者对于一个空列表,返回相同的东西begin返回。只要所有这些关系成立,一切都有效,无论您使用什么内部价值观或逻辑来保证关系。

答案 1 :(得分:5)

“一个结束”是根据迭代器遍历而不是内存位置来定义的。将迭代器作为最后一个元素并将其递增(或end一个空容器)时,可以获得begin迭代器。

std::forward_list指向nullptr的结束迭代器是有意义的:在实现中,最后一个节点可能有一个nullptr下一个节点,并且在该链接之后确实产生了{{1}迭代器。 end的{​​{1}}可能出于同样的原因在物理上指向存储区。

答案 2 :(得分:5)

  

end()应该是一个迭代器,指向'一个超过容器末尾的迭代器。

这与the standard says(强调我的)略有不同:

  

begin()返回一个迭代器,引用容器中的第一个元素。 end()返回一个迭代器,它是容器的 past-the-end 值。如果容器为空,则为begin() == end();

标准说"过去的结束"而不是"一个过去的结束"。

实施者可以自由选择"过去的结果"适用于特定的容器类型。

答案 3 :(得分:2)

  

对于非连续存储而言,“一个接一个结束”是什么意思?

只是最后一个有效节点指向的节点。

  

nullptr如何符合'一个接一个'的定义?

好吧,当您构建基于节点的数据结构时,最后一个有效节点将指向nullptr下一个节点,这就是您最终了解的结果。

  

如果MyForwardList.begin() == MyForwardList.end()为空,true MyForwardList怎么样?

在空列表中,标题为nullptr或标题为nullptr,因此将nullptrnullptr进行比较为true

  

为什么end()始终没有定义为nullptr?

因为没有要求你使用指针。