为什么reverse_iterator::base是偏移量?

Enr*_*lis 3 c++ iterator stl language-lawyer reverse-iterator

      +-- v.begin()           +-- v.end()\n      |                       |\n      v                       v\n    +---+---+---+---+---+---+ - +\n    | o | o | o | o | o | o | x |\n    +---+---+---+---+---+---+ - +\n\n+ - +---+---+---+---+---+---+\n| x | o | o | o | o | o | o |\n+ - +---+---+---+---+---+---+\n  ^                       ^\n  |                       |\n  +-- v.rend()            +-- v.rbegin()\n
Run Code Online (Sandbox Code Playgroud)\n

(从这个答案中复制并编辑了 ASCII ,这实际上促使我提出当前的问题。)

\n

我确实看到了这样做的好处&*rit == &*(rit.base() - 1),因为这样我就可以rit.base()对任何反向迭代器采用rit,并且我总是会得到一个有效的迭代器。

\n

但同时

\n
    \n
  • 我无法取消引用v.rbegin().base();我必须记住先减1 *(v.rbegin().base() - 1),,
  • \n
  • 我不能v.rend().base() - 1完全取消引用,因为我不能取消引用v.rend()
  • \n
\n

如果设计是这样呢&*rit == &*rit.base()

\n
    \n
  • 我们不能调用, true,但这只是对应于当前设计中v.rend().base()无法取消引用;v.rend().base() - 1
  • \n
  • 我们无法v.end()直接从反向迭代器获取,甚至是最接近的迭代器,b.rbegin()但这只是对应于- 1我们必须在当前设计中添加的rit.base(),以获得与反向相同元素的正向迭代器。
  • \n
\n

我的意思是,在我看来,无论设计决策是那样&*rit == &*(rit.base() - 1)还是那样&*rit == &*rit.base(),我们都会获得相同的便利

\n
    \n
  • rit.base()实际设计中总是没问题的,
  • \n
  • - 1在替代设计中通常不需要
  • \n
\n

和不便

\n
    \n
  • 无法rit.base()在实际设计中取消引用所有有效的 s,
  • \n
  • 需要+1 v.rbegin()进入v.end()替代设计,
  • \n
\n

只是在相反的情况下。

\n

所以我的问题是:做出确实做出的选择是否有明确的优势?或者这只是一枚抛硬币?

\n
\n

我发现第一个元素之前没有有效的迭代器,但这就是我的观点。std::prev(v.begin())当引入反向迭代器时,制作一个像这样的有效的、不可解引用的迭代器会有什么问题v.end()

\n
\n

事后看来,我确实看到了一个不容置疑的优势。

\n

我没有看到v.rbegin().base() == v.end()/的优点v.rend().base() == v.begin(),因为为什么我想从它们的反向对应项创建v.end()/ v.begin()

\n

但是,如果我有两个反向迭代器rit1并且rit2定义了 range (rit1, rit2],那么采用it1 = rit1.base()it2 = rit2.base()可以轻松引用相反方向的相同范围的元素,[it1, it2)

\n

长话短说:_我应该阅读《C++ 标准库 - 第二版》中的 \xc2\xa79.4.1。第一的。

\n

j6t*_*j6t 8

这不是一个设计决定,而是一个必然。

反向迭代器并不是一个神奇的东西,它能够以某种方式反向迭代一个范围。它是一个建立在已有事物之上的立面。

当您有一个包含 6 个条目的集合(如您的图片所示)时,您所拥有的只是 7 个可用迭代器值,仅此而已(6 个是可取消引用的,一个是最终迭代器值)。这就是反向迭代器可以构建的全部内容。

由于没有开始前的迭代器(就像第二张图片让人想到的那样),因此反向迭代器除了映射到rbegin()end()rend()之外没有其他选择begin()。也就是说,你有(rbegin() + i).base() == end() - i

反过来,这又要求可解除引用的迭代器(从 开始的前 6 个迭代器rbegin())实际上必须解除引用 iterator .base()-1。没有其他方法可以实现反向迭代器。

  • @Enlico:“*即使是后一个迭代器也是一种便利,与内存中的任何真实内容都不对应。*”但它确实如此。它可能不指向一个真实的对象,但它确实“存在”,因为它是一个有效的迭代器。C++ 标准要求,如果您有一个包含 X 个元素的数组,则可以获得指向第一个元素的指针,将其递增 X 次,并且仍然拥有一个可以有效递减的指针。相比之下,该标准不允许您递减指向数组第一个元素的指针;这样的操作就是UB。迭代器模型模仿指针行为。 (5认同)
  • @Enlico 标准库的迭代器是基于SGI模板库的设计的。SGI 模板库不是标准的一部分,无法对其进行任何更改。因此,它必须尽力而为。这仅适用于数组。对于链接列表,链接列表突然必须以某种方式容纳“be​​gin() 之前的一个”迭代器,这意味着显式代码。依此类推 - 每个容器都必须支持递减 begin()。这不是设计图书馆的方式。 (2认同)