STL源码笔记(9)—序列式容器之vector(二)

STL源码笔记(9)—序列式容器之vector(二)

vector的操作

在使用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简介

上述方法都是指针操作,比较好理解,这里有个地方引起了我的注意,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_iteratorstl_iterator.h文件中定义的一个模板类。
这个类有4个需要注意的地方:

  1. 数据类型
  2. base()返回当前指针
  3. *(解引用)操作符
  4. 构造函数
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总结

关于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的原因是之前提到解引用要自减
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值