使用std :: prev(vector.begin())或std :: next(vector.begin(), - 1)像some_container.rend()一样安全吗?

时间:2014-08-12 11:56:12

标签: c++ c++11 iterator reverse-iterator

我编写了一些代码来获取迭代器,但必须按相反的顺序进行比较,

template<class ConstBiIter>
bool func(ConstBiIter seq_begin, ConstBiIter seq_end)
{
    ConstBiIter last = std::prev(seq_end);
    while (--last != std::prev(seq_begin)) // --> I need to compare the beginning data
    {
        ......
    }
    return true;
}

在VS2013中,当在调试模式下运行时,--last != std::prev(seq_begin)将导致调试器断言失败,并显示错误消息

Expression:string iterator + offset out of range.

但在发布模式下运行并给出正确的结果时完全没问题,因为在发布模式下没有边界检查。

我的问题是:

  1. 使用std::prev(some_container.begin())some_container.rend()这样的哨兵是否安全?

  2. 如何直接将reverse_iteratoriterator进行比较?如果我写代码: std::cout << (std::prev(some_container.begin())==some_container.rend()) << std::endl;即使你reinterpret_cast,它也不会编译。

  3. 我很好奇prev(some_container.begin())在物理上等于some_container.rend()吗?

3 个答案:

答案 0 :(得分:9)

不,尝试减少开始迭代器是不安全的。

std::reverse_iterator(这是std::rend返回的内容)实际上并没有在开头迭代器之前包含迭代器。它将底层迭代器存储到它从概念上指向的下一个元素。因此,当反向迭代器是&#34;一个超过结束&#34; (即&#34;在开始之前&#34;)它的底层迭代器(通过调用base()获得)是开始迭代器。

答案 1 :(得分:2)

未定义的行为不安全,即使它今天在您的测试中有效。在C ++中,&#34;它在我尝试时起作用了#34;并不是你正确地做到这一点的好证据:最常见的未定义行为类型之一就是&#34;它似乎起作用了#34;。

问题是未定义的行为工作从根本上说是脆弱的。如果你用力呼吸就会破裂。

编译器可以自由地优化仅通过未定义的行为到达的分支和代码,并且在许多情况下就是这样。在服务补丁,编译器升级,传递给编译器的标志看似无关的变化或可执行路径名的长度之后,它甚至可以自由地这样做。它可以在99.9%的tge时间内自由工作,然后在0.1%的时间内对其他硬盘进行格式化。

其中一些比其他人更有可能。

虽然std::stringstd::vector元素的迭代器基本上都是发布中的指针,但编译器甚至可以键入一个指向迭代器的指针,即使下一个编译器版本使用包装指针时该假设也会失败

未定义的行为保留在C ++标准中,以允许编译器编写者自由地生成更优的代码。如果你调用它,你可以踩他们的脚趾。

话虽如此,有理由使用C ++标准未定义的行为。执行此操作时,请对其进行大量记录,隔离它,并确保支付(例如,委托速度是std::function的两倍)是值得的。

以上是非孤立的,不值得做未定义的行为,特别是因为你可以在没有未定义的行为的情况下解决它。

如果您想要向后迭代,最简单的解决方案是制作一些反向迭代器。

template<class ConstBiIter>
bool func(ConstBiIter seq_begin, ConstBiIter seq_end)
{
  std::reverse_iterator<ConstBiIter> const rend(seq_beg);
  for (std::reverse_iterator<ConstBiIter> rit(seq_end); rit != rend; ++rit)
  {
    ......
  }
  return true;
}

现在rfirst向后迭代范围。

如果你需要回到因任何原因而引用同一元素的前向迭代器,而你不是rend,你可以std::prev(rit.base())。如果此时rit == seq_end,那就是未定义的行为。

答案 2 :(得分:1)

24.5.1反向迭代器

  

类模板reverse_iterator是一个迭代器适配器,它从其底层迭代器定义的序列的末尾迭代到该序列的开头。反向迭代器与其对应的迭代器之间的基本关系由身份建立:&amp; *(reverse_iterator(i))==&amp; *(i - 1)。