代码:
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::distance 结合std::reverse_iterator::base() 来确定两个迭代器的相对位置。如果距离为零,则迭代器已经到达相同的元素;如果距离是负数,他们已经越过了。
(注意:否定情况需要C++11或更高版本,调用std::distance第一个参数“after”第二个是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
所以,我们需要将.base()迭代器的地址减去1,得到正确对应的forwards迭代器。下面给出的文档中的一行证实了这一点(但是,我发现他们的解释不清楚且难以理解,这就是我决定进行实际实验的原因):
那是&*(rit.base() - 1) == &*rit。
我无法比Mankarse's comment 更好地总结这一点:
考虑迭代器的一种简单方式是它们是光标
元素之间的位置。前向迭代器将产生
取消引用时光标后的元素,反向迭代器将
取消引用时生成光标之前的元素。相等的
正向和反向迭代器是相同的游标
位置。
为什么要减一?
反向迭代器具有这种与生俱来的非 1 差异,您可能会觉得很奇怪。似乎当反向迭代器位于位置i 时,它实际上指向位置i-1 的元素,即元素之前 i。
迭代器中有一种天生的不对称性可以解释这一点。考虑前向迭代器:我们可以拥有的“最早”和“最新”迭代器是什么?
最早的迭代器是指向集合的第一个元素的迭代器,而最新的迭代器指向集合的最后一个元素之后。
当我们反向迭代时,我们需要反向的相同功能。我们最早的反向迭代器应该直接指向最后一个元素,而我们最新的反向迭代器必须在第一个元素之前(或者从相反的角度来看,在第一个元素之后)。这些是允许我们遍历集合并知道我们何时访问过每个元素的基本语义。
我们现在看到正向视图和反向视图之间的自然对应导致了这种一对一的效果。如果我们设想我们的集合从左到右排序,最后一个元素位于倒数第二个位置,按前向顺序访问,但最右端位置以相反的顺序访问。但是,第一个元素正向位于最左位置,倒序位于最左第二个位置。
这是一个具体的例子。当我们的反向迭代器的base 对应于位置0 时,这表明它已经越过了起点(或反向终点)并完成了迭代。所以它指向位置0的元素
前一步,当它的base 位于1 位置时发生。然而,前向迭代器只是在位置0 处引用元素,而它位于位置0。