簡體   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