2
      +-- 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.base()用于任何反向迭代器rit,并且我总是会得到一个有效的迭代器。

但同时

  • 我不能取消引用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()实际设计中的所有有效 s,
  • 需要进入+1 v.rbegin()替代v.end()设计,

只是在相反的情况下。

所以我的问题是:做出确实已经做出的选择是否有明确的优势?或者它只是一枚翻转的硬币?

4

2 回答 2

5

这不是设计决定,而是必需品。

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

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

rbegin()由于没有 one-before-the-beginning 迭代器(就像第二张图片让人想到的那样),反向迭代器除了映射到end()rend()到之外别无选择begin()。也就是说,你有(rbegin() + i).base() == end() - i

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

于 2022-03-05T21:55:15.373 回答
1

在当前设计中,所有这些都按预期工作:

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

在您的替代设计中,不可能所有人都持有。如果基础&*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)在当前的设计中是不允许的,并且允许它会使迭代器是指针的数组无法使用反向迭代器,因为该语言禁止在第一个元素之前创建指针。

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

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

    这种方法只需要为反向迭代器引入过去开始。由于它们不是指针,这在理论上可能是可能的,但这需要额外的开销来表示比基本迭代器更多的迭代器状态。

    这两种选择都不是特别方便使用。

于 2022-03-05T22:14:35.220 回答