在使用vector
的时候,通常有一些操作来获取容器的状态以及访问容器中的元素,他们以vector
模板类中的方法来体现,我们在stl_vector.h
中可以看到它们的具体实现,例如:
template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
class vector : protected _Vector_base<_Tp, _Alloc>
{
//...
public:
iterator begin() { return _M_start; }
const_iterator begin() const { return _M_start; }
iterator end() { return _M_finish; }
const_iterator end() const { return _M_finish; }
reverse_iterator rbegin()
{ return reverse_iterator(end()); }
const_reverse_iterator rbegin() const
{ return const_reverse_iterator(end()); }
reverse_iterator rend()
{ return reverse_iterator(begin()); }
const_reverse_iterator rend() const
{ return const_reverse_iterator(begin()); }
size_type size() const
{ return size_type(end() - begin()); }
size_type capacity() const
{ return size_type(_M_end_of_storage - begin()); }
bool empty() const
{ return begin() == end(); }
reference operator[](size_type __n) { return *(begin() + __n); }
const_reference operator[](size_type __n) const { return *(begin() + __n); }
//...
reference front() { return *begin(); }
const_reference front() const { return *begin(); }
reference back() { return *(end() - 1); }
const_reference back() const { return *(end() - 1); }
};
上述方法都是指针操作,比较好理解,这里有个地方引起了我的注意,reverse_iterator
,记得我们要逆置容器的时候通常是可以这样的:
vector<int>vec;
vec.push_back(1);
vec.push_back(2);
vector<int>reverse_vec(vec.rbegin(), vec.rend());
cout << reverse_vec[0] << ","<<reverse_vec[1] << endl;//输出2,1
要知道逆置的原理,就得知道reverse_iterator
究竟是个什么东西:
首先,在stl_vector.h
文件中有如下定义:
template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
class vector : protected _Vector_base<_Tp, _Alloc>
{
//...
typedef value_type* iterator;
typedef const value_type* const_iterator;
//...
// 这里实际上是stl_iterator.h文件中定义的一个模板类
typedef reverse_iterator<const_iterator> const_reverse_iterator;
typedef reverse_iterator<iterator> reverse_iterator;
//...
};
reverse_iterator
是stl_iterator.h
文件中定义的一个模板类。
这个类有4个需要注意的地方:
- 数据类型
- base()返回当前指针
- *(解引用)操作符
- 构造函数
template <class _Iterator>
class reverse_iterator
{
protected:
_Iterator current;
public:
//构造函数
reverse_iterator() {}
explicit reverse_iterator(iterator_type __x) : current(__x) {}
//...
iterator_type base() const { return current; }
reference operator*() const {
_Iterator __tmp = current;
return *--__tmp;
}
}
这样很容易看出,实际上例如rbegin()
是以end()
为参数调用了reverse_iterator
的构造函数,这样current
指向了end()
也就达到逆序的目的。
还有一个令我疑惑的地方就在于,*(解引用)操作符,为何要自减一次?
于是做了一个测试:
vector<int>vec;
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
vec.push_back(4);
vector<int>::reverse_iterator it1 = vec.rend();
vector<int>::reverse_iterator it2 = vec.rbegin();
这里it1内部的指针应该指向vec中的第一个元素1,而it2指向vec中的最后一个元素的后一个位置(前闭后开),这样就不难理解自减的含义了,也正是因为这个原因,当我们直接访问it1时会报错:
cout << *it1<<endl;//error
it1中current
指针指向begin()
,而自减后就指向第一个元素的前一个位置了,这样就好像与“end()
表示最后一个元素的后一个位置”相呼应了。
最后,类中定义的base()
方法返回的是current
指针,这个函数外部可以访问,但是貌似一般不用,如果使用的话应该是如下形式吧:
vector<int>vec;
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
vec.push_back(4);
vector<int>::iterator it1 = vec.rend().base();
vector<int>::iterator it2 = vec.rbegin().base();
cout << *it1 << endl;//1
cout << *(it2 - 1) << endl;//4
关于reverse_iterator
就没有什么了,里面的任何操作都是对原指针相反的操作,不然怎么叫逆序迭代器呢?当我们使用rbegin()
和rend()
时,已经默认把容器倒着看了,但容器存储元素的顺序逻辑并没有改变,所以内部的指针操作相反,而又由于要与begin()和end()
的前闭后开相呼应,解引用的时候要自减1。
例如:
vector<int>vec;
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
vec.push_back(4);
//此时容器存储的顺序逻辑是1 2 3 4
auto it = vec.rend();//current实际指向begin(),而从类的角度来看,是指向begin()之前的位置
//it中current指针指向元素1
//cout<<*it<<endl;//error
it --;
//在内部current的操作为自增1
cout << *it<<endl;//这里是1不是2的原因是之前提到解引用要自减