为了支持STL的半开放范围的概念,我们可以指向数组的一个接一个的结尾。假设我们有一个三元素的向量。如果将std::vector::iterator
实现为指针(通常是发布版本中的情况),则begin
和end
指向这些位置:
+---+---+---+....
| | | | .
+---+---+---+....
^ ^
begin end
其中点表示一个过去的结束伪元素。既然没有一个在开头之前的东西,那么rend
究竟指向哪里?让我来说明一下:
+---+---+---+....
| | | | .
+---+---+---+....
^ ^
rend rbegin
显然,插图是错误的,因为rend
是非法指针。所以我想std::vector::reverse_iterator
的实现永远不会成为指针,即使在发布版本中也是如此。
我是对的吗?那么实施reverse_iterator
的最有效方法是什么?
答案 0 :(得分:5)
因为不允许取消引用指向容器外部的迭代器,所以rend()
“指向”实际上并不重要。它不必是合法的指针值,它可以是对容器/迭代器类型具有特定含义的任何值。
答案 1 :(得分:5)
rbegin
的结果与end
相同(结尾一个),rend
的结果与begin
相同(第一项) )。当取消引用反向迭代器时,它将返回对范围中前一项的引用。
答案 2 :(得分:3)
reverse_iterator
逻辑指向的内容与其包含的迭代器指向的内容之间存在差异。逻辑上,rbegin
产生一个指向序列最后一个元素的迭代器,rend
产生一个指向开始前一个元素的迭代器。但这通常使用一个基本迭代器实现,该迭代器指向反向迭代器指向的元素之后的一个元素。像这样:
template<class Iter>
class reverse_iter
{
Iter base;
public:
explicit reverse_iter(Iter it) : base(it) {}
reference operator*() const {
Iter tmp = base;
--tmp;
return *tmp;
}
reverse_iter& operator++() {--base; return *this;}
};
因此,如果使用reverse_iter<>
初始化这样的container.end()
对象,则基本迭代器指向结束的一个,但取消引用反向迭代器将为您提供最后一个元素。没有伤害。
答案 3 :(得分:2)
std::reverse_iterator
接口包含.base
成员函数,该函数检索与原始迭代器相等的迭代器。我怀疑他们通常做的只是缓存原始迭代器,并在operator * overload中偏移1。
答案 4 :(得分:1)
其他答案很好地回答了这个问题。
但是我也想知道它是否合法,因为假设一个实现可以在幕后做任何事情,只要它能够工作并符合标准。如果它选择将迭代器作为指针实现并选择取消引用,那么编译器有责任知道这将起作用。您无法以这种方式自己实现它,但在我看来,编译器作者有特殊许可来执行此操作,因为他们知道未定义的行为将是什么,并且不会直接将这种行为暴露给您,只是通过迭代器接口。