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。

posted @ 2019-04-23 08:23  吾之求索  阅读(168)  评论(0)    收藏  举报