检查反向迭代器是否已经越过前进迭代器

时间:2017-10-09 14:14:01

标签: c++

我有一个vector<int>::iterator和一个vector<int>::reverse_iterator,如下所示:

vector<int>::iterator start = array.begin();
vector<int>::reverse_iterator end = array.rend();
while (true)
{
    if (*start == *end && start <= end)
    {
        start++;
        end++;
    }
}

在while循环中,我必须检查start和end的值是否相等以及start是否未结束。在start <= end中执行此操作会给我错误。有人可以通过正确的方法指导我吗?

错误:

  

开始&lt; =结束。二元运算符&#39;&lt; =&#39;不能应用于vector :: iterator和reverse_iterator类型的表达式。

3 个答案:

答案 0 :(得分:3)

Vokay,我已经解决了,我就是这样做的:

    vector<int>::iterator start = array.begin();
    vector<int>::reverse_iterator end = array.rbegin();
    while (true)
    {
        if (*start == *end && start <= end.base())
        {
            start++;
            end++;
        }
        else
            break;
    }

我用rbegin替换了rend,因为那是事情出错的地方

答案 1 :(得分:2)

连续的迭代器并不比指针包装器多,找到指向的对象只需要通过迭代器获取指向的对象的地址。所以你可以这样做:

if (*start == *end && &(*start) <= &(*end)) { ...

如果您正在迭代像std::arraystd::vector这样的连续容器,则指针实际上指向同一底层原始数组的元素,因此比较指针是有效的。如果你在一个不连续的容器上进行迭代,比较迭代器根本就没有意义......

答案 2 :(得分:1)

代码:

std::vector<int> test_vector{0, 1, 2, 3};
std::vector<int>::iterator left_it = test_vector.begin();
std::vector<int>::reverse_iterator right_it = test_vector.rbegin();
while (std::distance(left_it, right_it.base() - 1) > 0) {
  ++left_it;
  ++right_it;
}
std::cout << "Iterators crossed" << std::endl;
std::cout << "*left_it = " << *left_it << ", *right_it = " << *right_it << std::endl;

输出:

Iterators crossed
*left_it = 2, *right_it = 1

我们结合使用std::distancestd::reverse_iterator::base()来确定两个迭代器的相对位置。如果距离为零,则迭代器到达相同的元素;否则,迭代器到达相同的元素。如果距离为负数,则表示它们已经交叉。

(注意:否定的情况要求 C ++ 11或更高版本,使用第一个参数“之后”调用std::distance,第二个参数在C ++ 11之前是未定义的行为)。


说明:

为了获得将反向迭代器与正向迭代器进行比较的基础,我们需要使用std::reverse_iterator::base()函数。但是,由于反向迭代器使用了一种实现技巧(请参阅下面的原因),因此您得到的结果恰好是您期望的结果之一。

为简要说明,我们可以遍历向量,并检查当前地址与向量的第一个元素的地址之间的偏移量。首先,我们有:

std::vector<int> test_vector{0, 1, 2, 3};
for (auto it = test_vector.begin(); it != test_vector.end(); ++it) {
  std::cout << &*it - &test_vector.front() << " ";
}

将按预期输出以下内容。

0 1 2 3

如果我们倒退,输出将反转:

for (auto rit = test_vector.rbegin(); rit != test_vector.rend(); ++rit) {
  std::cout << &*rit - &test_vector.front() << " ";
}

收益

3 2 1 0

但是,如果我们改为查看std::reverse_iterator::base()迭代器的地址,则会看到不同的内容:

for (auto rit = test_vector.rbegin(); rit != test_vector.rend(); ++rit) {
  std::cout << &*rit.base() - &test_vector.front() << " ";
}

收益

4 3 2 1

因此,我们需要从1迭代器的地址中减去.base(),以获得正确的对应正向迭代器。可以从下面给出的文档中确认这一点(但是,我发现它们的解释不清楚并且很难理解,这就是为什么我决定进行切实的实验):

  

&*(rit.base() - 1) == &*rit

我不可能比Mankarse's comment更好地总结一下:

  

一种简单的迭代器思考方式是它们是光标   元素之间的位置。前向迭代器将产生   取消游标后的元素,反向迭代器将   取消引用时在光标之前产生元素。当量   正向和反向迭代器是相同的游标   位置。



为什么要一个人走?

对于您来说,反向迭代器具有这种先天性的1比1差异可能会让您感到奇怪。似乎当反向迭代器位于位置i时,它实际上指向位置i-1处的元素,即元素之前 i

迭代器中固有的不对称性可以解释这一点。考虑正向迭代器:我们可以拥有的“最早”和“最新”迭代器是什么?

最早的迭代器是指向第一个元素的迭代器,而最新的迭代器则指向集合中最后一个元素之后的

当我们反向迭代时,我们需要反向相同的功能。我们最早的反向迭代器应直接指向最后一个元素,而我们最新的反向迭代器必须将指向在第一个元素之前(或从反向角度来看,在第一个元素之后)。这些是基本的语义,使我们可以遍历集合并知道何时访问了每个元素。

我们现在看到前视图和后视图之间的自然对应关系引发了这种一一对应的效果。如果我们设想从左到右排序我们的集合,则最后一个元素位于以向前顺序访问的第二到最右位置,但是位于最右位置反向访问。但是,第一个元素位于前进位置的最左位置,而相反的位置位于第二到最左侧的位置。

这是一个具体的例子。当我们的反向迭代器的base对应于位置0时,表明它已经超过起点(或反向终点)并完成了迭代。因此它指向位置0上的元素  提前一个步骤,当其base位于位置1时发生。但是,当元素位于位置0时,前向迭代器只是引用位置0的元素。