繁体   English   中英

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

[英]Can I convert a reverse iterator to a forward iterator?

我有一个名为Action的类,它本质上是一个围绕Move对象双端队列的包装器。

因为我需要向前和向后遍历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;
};

Advance功能如下:

void Action::Advance
{
    if( bForward)
        currentfwd++;
    else
        currentbck++;
}

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

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

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

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

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

不过,我更愿意返回一个引用,并将所有迭代细节封装在类中。

正是促使 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";
}

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

4
0
4
-1879048016
1
-1879048016

总结:使用rbegin()我们必须在转换为前向迭代器之前添加一个以获得有效的迭代器——但是使用rend()我们不能在转换为一个有效的迭代器之前添加一个。

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

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

由于std::deque是一个随机访问容器(与std::vector相同),因此您最好在两次遍历中使用单个整数索引进入双端队列。

在我看来,您实际上在同一个班级中有两种不同的行为。

值得注意的是,您似乎只能以一种顺序遍历您的集合,否则如果您要开始遍历然后更改bforward参数,您最终会bforward非常奇怪的情况。

就我个人而言,我完全赞成公开两个迭代器(即向前begin, end, rbegin and rend )。

您还可以返回一个简单的 Iterator 对象:

template <class T>
class Iterator
{
public:
  typedef typename T::reference_type reference_type;

  Iterator(T it, T end) : m_it(it), m_end(end) {}

  operator bool() const { return m_it != m_end; }

  reference_type operator*() const { return *m_it; }

  Iterator& operator++() { ++m_it; return *this; }

private:
  T m_it;
  T m_end;
};

template <class T>
Iterator<T> make_iterator(T it, T end) { return Iterator<T>(it,end); }

然后,您可以返回这个简单的对象:

class Action
{
public:
  Action(std::deque<Move> const& d): m_deque(d) {} // const& please

  typedef Iterator< std::deque<Move>::iterator > forward_iterator_type;
  typedef Iterator< std::deque<Move>::reverse_iterator > backward_iterator_type;

  forward_iterator_type forward_iterator()
  {
    return make_iterator(m_deque.begin(), m_deque.end());
  }

  backward_iterator_type backward_iterator()
  {
    return make_iterator(m_deque.rbegin(), m_deque.rend());
  }


private:
  std::deque<Move> m_deque;
};

或者,如果您想在向前和向后遍历之间动态选择,您可以使 Iterator 成为一个纯虚拟接口并同时具有向前和向后遍历。

但实际上,如果看起来你只会使用一个,我真的不明白同时存储向前和向后迭代器的意义:/

也许您应该重新考虑对容器的选择。

通常你不需要使用反向迭代器来倒退,

currentfwd--

会倒退,尽管它可能无法与出队一起工作(我假设您尝试过)。

您真正应该做的是将您的类建模为出队的装饰器并实现您自己的 Action 迭代器。 无论如何,这就是我要做的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM