我可以将反向迭代器转换为正向迭代器吗?

Bee*_*and 46 c++ iterator

我有一个叫做的类Action,它实际上是一个围绕Move对象deque的包装器.

因为我需要遍历Moves前向和后向的双端队列,所以我有一个前向迭代器和一个reverse_iterator作为类的成员变量.这样做的原因是因为当我前往或后退时,我需要知道何时离开了双端队的"终点".

这个类看起来像这样:

class Action
{
public:
    SetMoves(std::deque<Move> & dmoves) { _moves = dmoves; }
    void Advance();
    bool Finished() 
    {
        if( bForward )
            return (currentfwd==_moves.end());
        else
            return (currentbck==_moves.rend());
    }
private:
    std::deque<Move> _moves;
    std::deque<Move>::const_iterator currentfwd;
    std::deque<Move>::const_reverse_iterator currentbck;
    bool bForward;
};
Run Code Online (Sandbox Code Playgroud)

Advance功能如下:

void Action::Advance
{
    if( bForward)
        currentfwd++;
    else
        currentbck++;
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,我希望能够检索当前Move对象的迭代器,而无需查询我是向前还是向后.这意味着一个函数返回一种类型的迭代器,但我有两种类型.

我应该忘记返回一个迭代器,并返回一个Move对象的const引用 吗?

最好的祝愿,

BeeBand

Mik*_*our 65

反向迭代器有一个成员base(),它返回一个相应的前向迭代器.请注意,这不是引用同一对象的迭代器 - 它实际上是指序列中的下一个对象.这是rbegin()对应end()rend()对应的begin().

所以如果你想返回一个迭代器,那么你会做类似的事情

std::deque<Move>::const_iterator Current() const
{
    if (forward)
        return currentfwd;
    else
        return (currentbck+1).base();
}
Run Code Online (Sandbox Code Playgroud)

我宁愿返回一个引用,并将所有迭代细节封装在类中.

  • `(currentbck + 1).base()`当currentbck是一个结束迭代器时borks.在两者之间转换是一个等待发生的错误世界. (14认同)

Jer*_*fin 29

正是导致STL设计开始的问题.有充分理由:

  1. 不存储迭代器和容器
  2. 使用接受任意迭代器的算法
  3. 让算法一次评估整个范围而不是单个项目

我怀疑你现在看到的东西或多或少是真正问题的冰山一角.我的建议是退后一步,和而不是询问如何处理当前标准的设计细节,问你想要什么来实现,以及如何最好地实现这个目标有点更普遍的问题最终结果.

对于那些主要关注标题中问题的人来说,答案是严格限定的"是".特别是,reverse_iterator有一个base()成员来做到这一点.但资格有些问题.

演示问题,考虑这样的代码:

#include <iostream>
#include <vector>
#include <iterator>

int main() { 
    int i[] = { 1, 2, 3, 4};
    std::vector<int> numbers(i, i+4);

    std::cout << *numbers.rbegin() << "\n";
    std::cout << *numbers.rbegin().base() << "\n";
    std::cout << *(numbers.rbegin()+1).base() << "\n";

    std::cout << *numbers.rend() << "\n";
    std::cout << *numbers.rend().base() << "\n";
    std::cout << *(numbers.rend()+1).base() << "\n";
}
Run Code Online (Sandbox Code Playgroud)

在我的特定机器上的这个特定时刻运行它会产生以下输出:

4
0
4
-1879048016
1
-1879048016
Run Code Online (Sandbox Code Playgroud)

总结:rbegin()我们必须在转换为转发迭代器之前添加一个以获得有效的迭代器- 但是在转换为获取有效迭代器之前rend()我们不能添加一个迭代器.

只要您使用X.rbegin()X.rend()作为通用算法的参数,这很好 - 但经验表明转换为前向迭代器通常会导致问题.

然而,最后,对于问题的主体(与标题相对),答案几乎与上面给出的一样:问题源于尝试创建一个对象,该对象将集合与几个迭代器组合到该集合中.解决这个问题,使用正向和反向迭代器的整个业务变得没有实际意义.

  • 虽然这个答案有助于BeeBand它没有回答后代的原始问题.这个答案应该是对原帖的评论.我会请BeeBand考虑改变Mike Seymour的答案. (12认同)
  • 未来四年,我认为人们会发现这个问题,因为它的标题不仅仅是因为它的内容. (6认同)
  • @Lukasz:如果你将"问题"限制在标题中的内容,那你就是对的.但是,如果你自己阅读了整个问题,我会说的更多(充其量). (2认同)

Nik*_*sov 6

由于std::deque随机访问容器(与之相同std::vector),因此对于两次遍历,使用单个整数索引进入双端队列会更好.

  • 这就是为什么你总是需要第二双眼睛:) (2认同)