std::reverse_iterator如何在开始前保持一个?
How does std::reverse_iterator hold one before begin?
这是使用 std::reverse_iterator
的代码示例:
template<typename T, size_t SIZE>
class Stack {
T arr[SIZE];
size_t pos = 0;
public:
T pop() {
return arr[--pos];
}
Stack& push(const T& t) {
arr[pos++] = t;
return *this;
}
auto begin() {
return std::reverse_iterator(arr+pos);
}
auto end() {
return std::reverse_iterator(arr);
// ^ does reverse_iterator take this `one back`? how?
}
};
int main() {
Stack<int, 4> s;
s.push(5).push(15).push(25).push(35);
for(int val: s) {
std::cout << val << ' ';
}
}
// output is as expected: 35 25 15 5
当使用std::reverse_iterator
作为另一个迭代器的适配器时,新适配的end应该在原来的begin之前.但是在 begin 上调用 std::prev
是 UB。
开始前std::reverse_iterator
如何把握一个?
从迭代器初始化 std::reverse_iterator
不会在初始化时减少迭代器,因为在向它发送 begin 时它将是 UB(不能假设 std::prev(begin)
是一个有效的调用)。
技巧很简单,std::reverse_iterator
保留传递给它的原始迭代器,而不修改它。只有当它被取消引用时,它才会回头查看实际值。所以在某种程度上,迭代器指向内部的 next 元素,它可以从中获取当前的。
它看起来像:
// partial possible implementation of reverse_iterator for demo purpose
template<typename Itr>
class reverse_iterator {
Itr itr;
public:
constexpr explicit reverse_iterator(Itr itr): itr(itr) {}
constexpr auto& operator*() {
return *std::prev(itr); // <== only here we peek back
}
constexpr auto& operator++() {
--itr;
return *this;
}
friend bool operator!=(reverse_iterator<Itr> a, reverse_iterator<Itr> b) {
return a.itr != b.itr;
}
};
然而,这是一个内部实现细节(实际上可以以其他类似方式实现)。 std::reverse_iterator
的用户不必关心它是如何实现的。
这是使用 std::reverse_iterator
的代码示例:
template<typename T, size_t SIZE>
class Stack {
T arr[SIZE];
size_t pos = 0;
public:
T pop() {
return arr[--pos];
}
Stack& push(const T& t) {
arr[pos++] = t;
return *this;
}
auto begin() {
return std::reverse_iterator(arr+pos);
}
auto end() {
return std::reverse_iterator(arr);
// ^ does reverse_iterator take this `one back`? how?
}
};
int main() {
Stack<int, 4> s;
s.push(5).push(15).push(25).push(35);
for(int val: s) {
std::cout << val << ' ';
}
}
// output is as expected: 35 25 15 5
当使用std::reverse_iterator
作为另一个迭代器的适配器时,新适配的end应该在原来的begin之前.但是在 begin 上调用 std::prev
是 UB。
开始前std::reverse_iterator
如何把握一个?
从迭代器初始化 std::reverse_iterator
不会在初始化时减少迭代器,因为在向它发送 begin 时它将是 UB(不能假设 std::prev(begin)
是一个有效的调用)。
技巧很简单,std::reverse_iterator
保留传递给它的原始迭代器,而不修改它。只有当它被取消引用时,它才会回头查看实际值。所以在某种程度上,迭代器指向内部的 next 元素,它可以从中获取当前的。
它看起来像:
// partial possible implementation of reverse_iterator for demo purpose
template<typename Itr>
class reverse_iterator {
Itr itr;
public:
constexpr explicit reverse_iterator(Itr itr): itr(itr) {}
constexpr auto& operator*() {
return *std::prev(itr); // <== only here we peek back
}
constexpr auto& operator++() {
--itr;
return *this;
}
friend bool operator!=(reverse_iterator<Itr> a, reverse_iterator<Itr> b) {
return a.itr != b.itr;
}
};
然而,这是一个内部实现细节(实际上可以以其他类似方式实现)。 std::reverse_iterator
的用户不必关心它是如何实现的。