STL源码剖析 学C语言,STL源码剖析(一)

SLT简介

STL(Standard Template Library),即标准模板库,是一个高效的C++程序库。包含了诸多在计算机科学领域里经常使用的基本数据结构和基本算法。为广大C++程序员们提供了一个可扩展的应用框架,高度体现了软件的可复用性。其核心思想就是泛化编程(generic programming),在这种思想里,大部分基本算法被抽象,被泛化,独立于与之对应的数据结构,用于以相同或相近的方式处理各类不一样情形。node

STL组件

STL中包含了6大组件程序员

容器(Containers):包含各类基础的数据结构,如vector, list, deque, set, map等。

分配器(Allocators):负责空间配置与管理。

算法(Algorithms):各类经常使用的算法,如sort, search, copy, erase等等。

迭代器(Iterators):负责链接Containers与Algorithms。

适配器(Adapters):能够用来修饰Containers,Iterators和Functors接口的组件。

函数式(Functors):相似于函数,能够做为Algorithms的一种策略。

六大组件的关系

700d850ce7af9d483ab25c716150db71.png Containers 经过 Allocators 取得数据存储空间,Algorithms 经过 Iterators 存取 Containers 内容,Functors 能够协助 Algorithms 完成不一样的策略变,Adapters 能够修饰或套接Containers,Iterators和Functors。算法

容器

结构与分类

容器整体上分为三大类:编程

Sequence Containers(序列容器): Arrary(大小固定,没法自动扩充), Vector(只可向后扩充, 两倍的扩展), Deque(可向前或向后扩充, 分段连续, stack和queue都是基于此 ), List(双向链表), Forwaed-List(单向链表)

Associative Containers(关联容器):Set/Multiset, Map/Multimap(基本都用红黑树来实现)

Unordered Containers(无序容器): Unordered Set/Multiset, Unordered Map/Multimap(基本都是 HashTable Separate Chaining 实现)

1c3cbec22f2e99e9024438cfb5200f72.png

Array

是一种固定大小的容器类型,在定义的时候就要声明大小和类型。Array其实就是对C语言中数组的一种扩充升级,使其支持了迭代器的操做,便于STL算法的使用。array在使用和性能上都要强于内置数组,对于一些固定大小的使用场景,能够用array来替代原先数组的工做。数组

TR1版本源码以下:数据结构

template

struct array

{

typedef _Tp value_type;

typedef _Tp* pointer;

typedef balue_type* iterator;

value_type _M_instance[_Nm ? _Nm : 1];

iterator begin()

{ return iterator(&_M_instance[0]);}

iterator end()

{ return iteratoe(&_M_instance[_Nm]);}

...

};

Vector

Vector 使用起来和一个数组十分类似,可是在空间用完时,能够自动扩充本身的空间。通常而言空间的扩充,没法在原地完成扩充。因此会在内存中新申请一片内存(一般都是以前空间大小的2倍大),而后经过拷贝将原有数据拷贝到新的地址空间。框架

Vector中存在三个指针来代表Vector:dom

T* start:指向第一个元素的地址

T* finish:指向目前最后一个地址以后的一个空间的地址

T* end_of_storage:指向当前Vector的最后一个空间地址

须要注意的是:在空间(两倍)增加的过程当中涉及到了大量的拷贝构造和析构!函数

List

相较于vector的连续线性空间,List就显得复杂许多,它的好处是每次插入或删除一个元素,就配置或释放一个元素空间。所以,list对于空间的运用有绝对的精准,一点也不浪费。并且,对于任何位置的元素插入或元素移除,List永远是常数时间。性能

List不只是一个双向链表,并且仍是一个环状双向链表。 另外,还有一个重要性质,插入操做和接合操做都不会形成原有的List迭代器失效,这在Vector是不成立的。由于Vector的插入操做可能形成空间的从新配置,致使原有的迭代器所有失效。甚至List的元素删除操做(erase),也只有“指向被删除元素”的那个迭代器失效,其余迭代器不受任何影响。

Forward-List

Forward-List容器与List容器的主要设计区别是List保持内部惟一的一个连接到下一个元素,然后者则保持每一个元素的两个连接:一个指向下一个元素和一个前一个。容许高效在两个方向迭代,但每一个元素的消耗额外的存储空间,并轻微较高的时间开销插入和删除元素的迭代。Forward-List对象,从而比List对象更有效率,虽然他们只能向前遍历。

因此Forward-List的一个最大的缺点就是没法直接访问指定位置上元素,每次一的访问都须要从头开始访问,这样的操做须要线型的时间。

Deque

5338923ffd645397e617cfdd93c4bf91.png

能够向两端扩充,经过指针链接不一样分段的空间,模拟出连续空间。

template

class deque{

public:

typedef T value_type;

typedef __deque_iterator iterator;

protected:

typedef pointer* map_pointer;//T**

protected:

iterator start;

iterator finish;

map_pointer map;

size_type map_size;

public:

iterator begin(){return start;}

iterator end(){return finish;}

size_type size(){return finish-start;}

...

};

template

struct __deque_iterator{

typedef random_access_iterator_tag iterator_category;

typedef T value_type;

typedef Ptr pointer;

typedef Ref reference;

typedef size_t size_type;

typedef ptrdiff_t difference_type;

typedef T** map_pointer;

typedef __deque_iterator self;

T* cur;

T* first;

T* last;

map_pointer node;

...

};

start指向第一块分区,finishi指向最后一块分区,map是用来存放各个分区的地址(vector实现),map_size是map的大小。 start和finish做为iterator,cur指向当前的元素,first指向第一个存放的元素,last指向当前分区中最后一个存放的数据以后的位置,node指回map。

deque 如何模拟连续空间?

基本所有依靠deque iterators完成

reference operator*() const

{

return *cur;

}

pointer operator->() const

{

return &(operator*());

}

difference_type operator-(const self& x) const

{

return difference_type(buff_size()) * (node - x.node - 1) + (cur - first) + (x.last - x.cur);

}

self& operator++(){

++cur;

if(cur == last){

set_node(node + 1);

cur = first;

}

return *this;

}

self operator++(int){

self tmp = *this;

++*this;

return tmp;

}

self& operator--(){

if(cur == first){

set_node(node - 1);

cur = last;

}

--cur;

return *this;

}

self operator--(int){

self tmp = *this;

--*this;

return tmp;

}

void set_node(map_pointer new_node){

node = new_node;

first = *new_node;

last = first + difference_type(buffer_size());

}

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;

set_node(node + node_offset);

cur = first + (offset - node_offset * difference_type(buffer_size()));

}

return * this;

}

self operator+(difference_type n) const {

self tmp = *thisl

return tmp +=n;

}

self& operator-=(fifference_type n)

{

return *this += -n;

}

self operator-(difference_type n) const

{

self tmp = * this;

return tmp -= n;

}

reference operator[](difference_type n) const

{

return *(*this + n);

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值