11

我写了一些带有迭代器但必须以相反顺序进行比较的代码,

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 中,在 Debug 模式下运行时,--last != std::prev(seq_begin)会导致调试器断言失败,并显示错误消息

Expression:string iterator + offset out of range.

但是在 Release 模式下运行并给出正确的结果是完全可以的,因为在 Released 模式下没有边界检查。

我的问题是:

  1. std::prev(some_container.begin())像哨兵一样使用安全some_container.rend()吗?

  2. 如何直接比较 areverse_iterator和 a iterator?如果我写代码: std::cout << (std::prev(some_container.begin())==some_container.rend()) << std::endl;它不会编译,即使你是reinterpret_cast他们。

我很好奇身体上是否prev(some_container.begin())相等?some_container.rend()

4

3 回答 3

11

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

std::reverse_iterator(这是由返回的std::rend)实际上在下面并不包含在开始迭代器之前的迭代器。它将一个底层迭代器存储到它概念上指向的下一个元素。因此,当反向迭代器是“一个过去的结尾”(即“开始之前”)时,它的底层迭代器(您通过调用获得base())是开始迭代器。

于 2014-08-12T12:02:07.267 回答
7

未定义的行为是不安全的,即使它今天在您的测试中有效。在 C++ 中,“它在我尝试时有效”并不能很好地证明您做得正确:最常见的未定义行为类型之一是“它似乎有效”。

问题是未定义的行为工作基本上是脆弱的。如果你用力呼吸它可能会破裂。

编译器可以自由地优化分支和仅通过未定义行为到达的代码,并且在许多情况下就是这样做的。在服务补丁、编译器升级、传递给编译器的标志的看似无关的更改或可执行路径名称的长度之后,它甚至可以免费这样做。它可以免费在 99.9% 的时间内正常工作,然后在其他 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那时,那是未定义的行为。

于 2014-08-12T14:08:43.007 回答
1

24.5.1 反向迭代器

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

于 2014-08-12T12:39:30.397 回答