操作符重载
deque底层实际上是将元素在一段段内存中存储起来,然后每一段的起始地址是通过一个vector的数组进行管理的。为了实现逻辑上的连续,所以针对iterator的设计来说,是需要重载各种操作符的。
首先现在这里说一下接下来经常看到的一个self,这个定义是
typedef __deque_iterator self;
其实就是iterator的别称。
基本的函数
reference operator*() const{return *cur;}
pointer operator-> const{ return &(operator*());}
reference operator[](size_type n){
return start[difference_type(n)];
}
reference front(){return *start;}
reference back(){
iterator tmp = finish;
--tmp;
return *tmp;
}
size_type size() const{return finish -start;}//这里需要重载运算符-
bool empty() const{return finish == start;}
在这里要强调的是size()这个函数,因为是要算所有的段中的元素,因此我们是需要重载-这个操作符的
重载‘-’
长度是有三部分组装成:队头的段中元素的个数、队列中的段的元素的个数、队尾的段中的元素的个数。
difference_type operator-(const self& x) const{
return difference_type(buffer_size()) * (node - x.node - 1) + (cur - first) + (x.last - x.cur);
//cur-first表示deque最后一段的现有的元素
//x.last-x.cur表示deque第一段的现有的元素
}
重载’++’/’–’
重载++只需要注意是否会跨段访问。
self& operator++(){
++cur;
if(cur == last){
set_node(node + 1);//到下一个缓冲区
cur = first;
}
return *this;
}
同理‘–’也要注意是否会跨段访问
self& operator--(){
if(cur == first){
set_node(node - 1);
cur = last;
}
--cur;
return *this;
}
两者唯一的区别就是对于++而言是沿着first->cur->last增长的;–是沿着last->cur->first增长的。
set_node的功能是在中央控制单元map_pointer控制节点,也就是控制存储段地址的空间。这里要注意一点的是,map_pointer底层虽然是vector,但是在扩容的时候有一点区别。vector一般扩容搬运元素的时候是从新开的空间的空间头开始的;但是因为deque是一个双向的,也就是有可能在头/尾加新的node。在这种情况下,我们在vector扩容,我们不应该是从新空间的头开始填充,而应该是从中间填充的,这样才可以保证deque的新节点插入的时候,是可以充分利用空间的。
void set_node(map_pointer new_node){
node = new_node;
first = *new_node;
last = first + difference_type(buffer_size());
}
重载’+n’/’-n’
因为需要模拟随机访问的特性,因此需要重载所有的对指针进行‘+’或者‘-’.因为‘-’相当于‘+’个负数,因此我们只需要重载‘+’便可以完成上述的所有的功能的。调用‘+’实际上是通过重载‘+=’实现的。
self operator+(difference_type n) const{
self tmp = *this;
return tmp += n;
}
//重载+=
self& operator+=(difference_type n){
difference_type offset = n + (cur - first);
if(offset >= 0 && offset < difference_type(buffer_size())){
//目标位置在同一个段里面
cur += n;
}else{
//目标位置跨段了
//找到需要跨越几个段
difference_type node_offset = offset > 0 ? offset / difference_type(buffer_size())
: - difference_type((-offset - 1) / buffer_size()) - 1;
//去中央控制器找相对应的node的入口
set_node(node + node_offset);
//移动到正确的位置
cur = first + (offset - node_offset * difference_type( buffer_size() ));
}
return *this;
}
同理,-n只需要调用+(-n)就好了。因为在重载+=的时候,我们已经判断offset的正负决定是往哪个方向移动。
self operator-(){
self tmp = *this;
return tmp -= n;
}
self& operator-=(difference_type n){
return *this += -n;
}