簡體   English   中英

為什么 reverse_iterator::base 偏移量?

[英]Why is reverse_iterator::base offset?

      +-- v.begin()           +-- v.end()
      |                       |
      v                       v
    +---+---+---+---+---+---+ - +
    | o | o | o | o | o | o | x |
    +---+---+---+---+---+---+ - +

+ - +---+---+---+---+---+---+
| x | o | o | o | o | o | o |
+ - +---+---+---+---+---+---+
  ^                       ^
  |                       |
  +-- v.rend()            +-- v.rbegin()

(ASCII 從這個答案復制和編輯,這實際上促使我問現在的問題。)

我確實看到了&*rit == &*(rit.base() - 1)的優勢,因為這樣我就可以為任何反向迭代器rit使用rit.base()並且我總是會得到一個有效的迭代器。

但同時

  • 我不能取消引用v.rbegin().base() 我必須記住先減去 1, *(v.rbegin().base() - 1)
  • 我不能取消引用v.rend().base() - 1正是因為我不能取消引用v.rend()

如果設計是&*rit == &*rit.base()怎么辦?

  • 我們不能調用v.rend().base() ,是的,但這僅僅對應於不能在當前設計中取消引用v.rend().base() - 1
  • 我們無法直接從反向迭代器中獲取v.end() ,甚至是最接近的迭代器b.rbegin() ,但對於- 1我們必須添加到rit.base()中當前的設計是將正向迭代器指向與反向相同的元素。

我的意思是,在我看來,設計決定是&*rit == &*(rit.base() - 1) (原樣)還是&*rit == &*rit.base() ,我們會有同樣多的便利

  • rit.base()在實際設計中總是可以的,
  • - 1在替代設計中通常不需要

和不便

  • 不能在實際設計中取消引用所有有效的rit.base()
  • 需要+1 v.rbegin()才能在替代設計中獲得v.end()

只是在相反的情況下。

所以我的問題是:做出確實已經做出的選擇是否有明確的優勢? 或者它只是一個翻轉的硬幣?


我看到在第一個元素之前沒有有效的迭代器,但這就是我的意思。 當引入反向迭代器時,讓std::prev(v.begin())v.end()一樣成為有效的、不可解引用的迭代器會有什么問題?


事后看來,我確實看到了一個毋庸置疑的優勢。

我沒有看到v.rbegin().base() == v.end() / v.rend().base() == v.begin()的優勢,因為我為什么要創建v.end() / v.begin()來自他們的反向對手?

但是,如果我有兩個定義范圍(rit1, rit2]的反向迭代器rit1rit2 ,那么采用it1 = rit1.base()it2 = rit2.base()可以輕松地引用相反范圍內的相同元素方向, [it1, it2)

長話短說:_我應該閱讀The C++ Standarl Library - 2nd ed 中的 §9.4.1。 第一的。

這不是設計決定,而是必然。

反向迭代器並不是某種能夠以某種方式反向迭代范圍的神奇事物。 它是建立在已經存在的事物之上的立面。

當您有一個包含 6 個條目的集合時(如您的圖片所示),那么您所擁有的只是 7 個可用的迭代器值,僅此而已(6 個是可取消引用的,一個是結束迭代器值)。 這就是反向迭代器可以構建的全部內容。

由於沒有先於開始的迭代器(就像第二張圖片讓人想到的那樣),因此對於反向迭代器,除了將 map rbegin()end()rend()begin()之外別無選擇。 也就是說,你有(rbegin() + i).base() == end() - i

這反過來又要求可取消引用的迭代器(從rbegin()開始的前 6 個)實際上必須取消引用迭代器.base()-1 沒有其他方法可以實現反向迭代器。

在當前設計中,所有這些都按預期工作:

std::make_reverse_iterator(it).base() == it;
auto rbegin = std::make_reverse_iterator(end);
auto rend   = std::make_reverse_iterator(begin);

在您的替代設計中,不可能所有的人都持有。 如果 base &*rit == &*rit.base()那么

  • 要么你必須構造一個偏移量:

     auto last = std::prev(end) auto rbegin = std::make_reverse_iterator(last); auto pastbegin = std::prev(begin); // not allowed: auto rend = std:;make_reverse_iterator(pastbegin);

    這將需要將迭代器的概念引入到不存在的“第一個元素之前”。 std::prev(begin)在當前設計中是不允許的,並且允許它會使迭代器是指針的 arrays 的反向迭代器變得不可能,因為該語言禁止在第一個元素之前創建指針。

  • 或者你必須在施工后抵消

    auto rpastbegin = std::make_reverse_iterator(end); auto rbegin = std::next(rpastbegin); auto rlast = std::make_reverse_iterator(begin); auto rend = std::next(rlast);

    這種方法只需要為反向迭代器引入 past begin。 由於它們不是指針,理論上這可能是可能的,但這將需要額外的開銷來表示比基本迭代器更多的迭代器狀態。

這兩種選擇都不是特別方便使用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM