C++-关于容器的reverse_iterator的疑问
看cplusplus和cppreference的上的解释
Notice however that when an iterator is reversed, the reversed version does not point to the same element in the range, but to the one preceding it. This is so, in order to arrange for the past-the-end element of a range: An iterator pointing to a past-the-end element in a range, when reversed, is changed to point to the last element (not past it) of the range (this would be the first element of the range if reversed). And if an iterator to the first element in a range is reversed, the reversed iterator points to the element before the first element (this would be the past-the-end element of the range if reversed).
std::reverse_iterator相反的方向一个给定的迭代器是一个迭代器适配器。换句话说,当设置有一个双向迭代,std::reverse_iterator产生一个新的迭代器,它从端部移动到由底层双向迭代器定义的序列的开头.
从一个迭代器r构造一个反向迭代器i的关系&r == &(i-1)总是如此,因此构建一个反向迭代器从一个过去的结束迭代器解引用序列中的最后一个元素.
这里的意思是反向迭代器reverse_iterator总是指向前一个元素吗。
关于原来的iterator可以通过调用base()获得,并且它总是指向下一个元素。
The base iterator is an iterator of the same type as the one used to construct the reverse_iterator, but pointing to the element next to the one the reverse_iterator is currently pointing to (a reverse_iterator has always an offset of -1 with regards to its base iterator).
#include <iostream>
#include <stdlib.h>
#include <vector>
#include <algorithm>
using namespace std;
template<class C>
typename C::iterator find_last(C& c, typename C::value_type v) {
typename C::reverse_iterator ri = find(c.rbegin(), c.rend(),v);
if (ri == c.rend()) return c.end();
typename C::iterator i = ri.base();
return --i;
}
template<class C>
typename C::reverse_iterator find_last1(C& c, typename C::value_type v) {
typename C::reverse_iterator ri = find(c.rbegin(), c.rend(),v);
if (ri == c.rend()) return ri;
return ri;
}
int main()
{
vector<int> vec;
for(int i = 0; i < 10; i++) {
vec.push_back(i);
}
vector<int>::iterator it = find_last(vec, 11);
cout << &*it << endl;
it = find_last(vec,9);
cout << *it << endl;
cout << &*it << endl;
vector<int>::reverse_iterator rit = find_last1(vec, 11);
cout << &*rit << endl;
rit = find_last1(vec, 9);
cout << *rit << endl;
cout << &*rit << endl;
return 0;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在这里需要弄清楚逻辑位置和实际位置二者的区别。
下图显示了逆向迭代器的位置和所指的数值:
可以发现,逆向迭代器所指位置(实际位置)和所代表的的数值(逻辑位置或数值)是不同的。C++这么做是有其原因的。导致这个行为的原因是区间的半开性。为了能够制定容器内的所有元素,我们必须运用最后一个元素的下一个位置。但是对于reverse迭代器而言,这个位置位于第一个元素之前。这时候问题就出现了,这个位置也许并不存在,因为容器并不要求其第一个元素之前的位置合法。
因此,逆向迭代器运用了一个小技巧:实际上倒置了“半开原则”,即逆向迭代器所定义的区间不包括起点,而包括终点。但是逻辑上一如常态。这样就导致了逆向迭代器实际所指的元素位置和逻辑上所指的元素位置就不一致。
下面再看看将一个迭代器转化为逆向迭代器的过程:
可以发现,迭代器的实际位置(元素)不变,但是逻辑位置(元素)发生了变化。图中pos迭代器转化为逆向迭代器rpos后实际位置还是5,但是逻辑位置是4.即逻辑元素位置是实际位置的前一个位置。测试代码:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
vector<int> coll;
//insert elements from 1 to 9
for (int i=1; i<=9; ++i) {
coll.push_back(i);
}
//find position of element with value 5
vector<int>::iterator pos;
pos = find (coll.begin(), coll.end(),
5);
//print value to which iterator pos refers
cout << "pos: " << *pos << endl;
//convert iterator to reverse iterator rpos
vector<int>::reverse_iterator rpos(pos);
//print value to which reverse iterator rpos refers
cout << "rpos: " << *rpos <<endl;
}
输出结果是
举一个形象的例子:
对于 left_null——>1——>2——>3——>4——>right_null ,这样一个有4个元素(1,2,3,4)的链表。
1. 看看正向的begin和end是指向哪里和怎么操作的:
list<int>iteraotr c1=intList.begin()//*c1=1;
list<int>iteraotr c2=intList.end()//*c2=right_null;
iterator++,则对于上边正向链表从左向右遍历。
for(c1=.begin(),c1!=.end();c1++)
cout<<...1,2,3,4
2. 看看反向的rbegin和rend是指向哪里和怎么操作的:
list<int>reverse_iteraotr c1=intList.rbegin()//*c1=4; rbegin相当于reverse_begin即反着看的头。
list<int>reverse_iteraotr c1=intList.rend()//*c1=left_null; rend相当于reverse_end即反着看的尾。
reverse_iterator++,则对于上边正向链表从右向左遍历。
for(c2=.rbegin();r2!=.rend();c2++)
相当于:4 3 2 1
for(c2=rend(),c2!=.rbegin().......)-->没有这种用法,因为不存在rend()指向的元素!!!
rend()返回的迭代器指向 第一个元素的前一个,也就是 0 之前那一个
end()返回的迭代器指向 最后一个元素的后一个,就是 9 之后那一个
他们能一样吗?
当找到的时候,你在 find_last 里面,返回 i 之前,执行了 --i,那么 rit 和 it 的地址一样,不也是符合 &r == &(i-1) 的吗?
你的理解没有错,估计是一时犯糊涂了。