使用rbegin()和begin()进行反向迭代

3

当我们以相反的方向迭代时,我发现大多数人使用以下结构:

for (auto it = vec.rbegin(); it != vec.rend(); it++)
{
    // block of code //
}

然而,我长期以来一直对使用它有疑问,并想知道为什么以下代码无法正常工作。

我们知道,最后一个元素的索引比数组中任何元素的索引都要高,并且数组将占用连续的内存。

我的主要疑问是在反向迭代时,为什么不应该使用 it--

我想知道以下代码不起作用的原因。我从 rbegin 开始循环,也就是最后一个元素,一直到第一个元素。在每次迭代中,我将 it 减少一。

for (auto it = vec.rbegin(); it >= vec.begin(); it--)
{
    cout << *it << endl;
}

即使以下代码也不可用,为什么?
for(auto it = vec.rbegin(); it >= vec.begin(); it++)
{
    cout << *it << endl;
}

++是用于推进迭代器的运算符,即使是向后的迭代器也是如此。你需要向后多走一步(因此是++)。请注意,在C++20中,您还可以使用https://en.cppreference.com/w/cpp/ranges/reverse_view,这可能更有意义。 - Pepijn Kramer
1
你能解释一下为什么你认为 FOR(auto it=vec.rbegin();it>=arr.begin();it++) 会起作用吗?FOR - 这是一个宏吗?vecarr 是什么?比较反向迭代器和普通迭代器? - Ted Lyngmo
1
你可以将rbegin()理解为一个特殊指针的数据结构,其中++运算符被重载为--。总的来说,这只是一个设计问题。如果你使用得更多,你可能会意识到这样的统一设计在使用中有许多好处。 - Xin Cheng
2
最好不要将rbegin()指针与begin()进行比较,因为它们是不同的东西。考虑一个列表{1,2}begin()指向1,rbegin()指向2,end()指向2之后的位置,rend()指向1之前的位置。 - Xin Cheng
“not working”在描述问题时并不是很有用。你应该阅读编译器的错误信息,通常它包含了很多有用的信息。如果你不理解错误信息,没关系,把它包含在问题中,其他人可以解释。 - 463035818_is_not_a_number
显示剩余2条评论
3个回答

4

首先,在给定的代码中,for循环的条件由于类型不匹配而出现问题。

vec.rbegin() 给出了 std::vector::reverse_iterator,而 vec.begin() 给出了 std::vector::iterator它们是不同的类型,因此不能进行比较。因此,在这些地方你会得到编译器错误。


迭代倒序时,为什么我们不应该使用 it--

请参见来自 std::reverse_iterator 的以下参考图片:

enter image description here

当你使用 rbegin() 时,你从最后一个元素开始。为了继续前进(就像每个迭代器实现一样),它使用 operator++。 这里的前进意味着向后迭代,因为起点是最后一个元素。因此,你应该使用 it++++it


然而,在最后一个for循环示例中,只存在类型不匹配的问题。使用 std::reverse_iterator::base(),你可以获取/转换反向迭代器到相应的基本迭代器,并将它与 vec.begin() 进行比较。

这意味着以下更改将使其正常工作:

for (auto it = vec.rbegin(); it.base() != vec.begin(); ++it)
//                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
   std::cout << *it << " ";
}

查看演示


附注:


0
总的来说,这只是一个设计问题,设计师以那种方式设计了beginrbeginendrend
以一个包含三个元素{1,2,3}的容器为例。
  • begin()指向1end()指向3之后的位置
  • rbegin()指向3rend()指向1之前的位置。
你可以将rbegin()理解为一个特殊的数据结构,它有一个特殊的指针(也称为迭代器),使得+运算符被重载为-
你可以使用rbegin()begin()混合使用,但不建议这样做,因为它们是不同的东西。而且大多数情况下混合使用总是容易出错的。

这只是一个演示,展示了 begin()rbegin()。它并不意味着显示基本用法。上面的例子的目的并不是展示正确的方式,只是为了比较和展示我的描述的想法。感谢 @JeJo。 - Xin Cheng

0

反向迭代器旨在模仿正向迭代器(而迭代器总体上旨在模仿指针),因此可以编写一种不受类型限制的算法,适用于两种类型。所有迭代器都使用operator++前进并使用operator--后退,其中:

  • 正向迭代器向前方向前进并向后方向后退

  • 反向迭代器向后方向前进并向前方向后退


是的,但我也单独为反向迭代器编写了它++,但代码还没有运行,我的确切疑问是我从vec.rbegin()即最后一个元素开始,一直到vec.begin()即第一个元素,但代码不运行,请为我澄清这个疑问。 - Peicherla Asrith Varma
正如其他人已经指出的那样,@PeicherlaAsrithVarma,您正在混合使用不同类型的迭代器,这是未定义行为。使用rbegin()时,您需要向rend()迭代,而不是begin()。它们不是同一件事。您是否阅读过 https://en.cppreference.com/w/cpp/iterator/reverse_iterator? - Remy Lebeau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接