C++-----STL与泛型编程(二)
此系列博客,图片文字观点均是来自侯捷老师讲义课程,仅作为学习用途。
1、源代码之分布
源码之前,了无秘密。标准库是指标准接口,但是具体实现可能会有细微不同。
VS2015的目录下include目录下:里面含有标准库的源码。

DEV-C++的源码也是在其目录下的include中。
2、面向对象编程OPP和泛型编程GP
标准库其实并不是在面向对象的思想下编写的,面向对象一般是有各种类,类与类之间有继承关系。但是标准库是在泛型编程的思想编写的。
OOP是将datas(数据)和method(操作)放在一起。GP却是将datas(数据)和method(操作)分开。

算法调用迭代器,迭代器访问容器元素。
采用GP的优点:容器Containers和算法Algorithms可以相互不影响,各自开发,中间使用Iterator沟通即可。算法通过Iterator取用Container。
那为什么有的容器包含sort函数有的不包含呢?首先不包含sort函数的容器,也就是说,这些自身不含sort函数的容器,使用的是全局的sort函数进行排序,这些容器也就是采用的泛型编程的思想。全局的sort函数的实现依赖于一种随机访问迭代器的操作。那些含有自己的排序函数的容器并不支持这种迭代器,所以这些容器会有自己的sort函数。查看了C++目前涉及的容器,只有list含有自己的sort函数,其余的如果要排序均要使用标准库的sort函数。
3、操作符重载、模板
阅读源码两个最主要的基础:操作符重载和模板。
有四个操作符不能被重载(:: . .* ?:)。

模板一般包括类模板和函数模板,还有成员模板(几乎不用)。
类模板需要用使用<>指明具体是什么类型。函数模板是不需要的,因为它会进行实参推导。
泛化:

特化:

泛化:
![]()
特化:
![]()
Alloctor:

偏特化:只特化其中一部分,局部特化,在模板参数上进行局部。

偏特化:范围上的偏特化。

4、分配器
分配器是给容器用的,一般的开发中不会使用到。分配器的效率是很重要的。分配器是给容器分配内存的。
operator new()和malloc(),所有的operator new其实都是在调用malloc()。malloc()调用的返回的其实比你需要的要多一点。如下图:

STL中使用allocator如下:

VC6.0的标准库中allocator的实现如下:

BC5的和VC差不多。GNU C的标准库其中allocator实现如下:

和前面的源码一样,三者的分配器最终都是使用operator new和operator delete。而上面两个函数的最终调用是malloc和free。以前面的分配内存来看,如果你申请的区块大,那么最后的额外开销小,如果申请的区块小,最后额外开销大。上面这个分配器其实在源码中没有被使用,上图中字段有说明。
GNU 2.9中STL中对allocator的调用如下图:可以看到,其实并没有使用到allocator而是使用的alloc这个类。
而alloc的实现如下图:使用16个链表,第一条链表负责8字节,第二条负责8*2,第三条8*3,这样16个链表各自管理的大小分别是8,16,24,32,40,48,56,64,72,80,88,96,104,112,120,128的小额区块。

SGI源码设计了双层级分配器,第一级分配器直接使用malloc和free,第二季分配采用不同的策略,当分配空间大于128字节时调用一级分配器,小于128字节时,采用内存池管理方式,其实就是alloc。为了方便管理,第二季分配器会主动将小额区块的内存需求量上调到8的倍数,比如要求30个字节,就调整为32字节。每次申请一大块内存,慢慢切割来使用,减少cookies的不必要浪费。
在GNU C4.9里面STL对allocator的使用:可以看到并没有使用上面的alloc,而是又回到之前使用的operator new和operator delete。


而在2.9版本中的alloc其实在4.9里面还是存在的,只是改了名字,变成了_pool_alloc。

5、容器的结构与分类
序列式容器:

上图的含义是,heap还有priority_queue其实就是是使用vector实现的。下面同理,stack和queue是通过deque实现的。左边的含义是sizeof()之后的大小,可以看出其实和容器里面放的元素个数是没有关系的。在C++11中,slist,名为forward_list。
关联式容器:

同上,set,map,multiset,multimap是通过rb_tree实现的,hash_set,hash_map,hash_multiset,hash_multimap是通过哈希表实现的,在C++11中,hash_set,hash_map,hash_multiset,hash_multimap改名为unordered_set,unordered_set,unordered_map,unordered_multiset,unordered_multimap。

浙公网安备 33010602011771号