看视频记录的超简单的笔记以及一些C++资料,为了以后复习mark一下
[侯捷]C++体系结构与内核分析
大佬的C++那些事儿
STL六大部件
容器(Containers)
顺序容器:Array、Vector、Deque、List、Forward_list
关联容器:Set/Multiset、Map/Mulitimap
不定序容器:Unordered Set/Multiset、Unordered Map/Multimap
分配器(Allocators):class template
算法(Algorithms):function template
迭代器(Iterators):class template
适配器(Adapters):class template
仿函式(Functors):class template
一、allocators
1、前言
malloc
分配出来的内存块长这样:
上下两个红块是这个块的边界,因为有这样一个边界,还内存的时候才可以只传递一个指针。正是因为有这么多的额外开销,所以malloc
的开销很大。
2、正文
模板类里面主要是有一个allocate
和deallocate
方法(以下是VC6里的源码样子,和BC5、G2.9里实现的大致差不多)
allocate
负责分配内存,传入两个参数:要分配多大的空间,类型为size_type
和随便什么参数,类型为const void*
,没有参数名。最终调用的还是operator new()
方法(归根结底是malloc()
)。
deallocate
负责释放内存,传入两个参数:内存首地址和内存空间大小。最终调用的是operator delete()
方法(归根结底是free()
)。
使用示例:
//分配 512 ints.
int *p = allocator<int>().allocate(512, (int*)0);
allocator<int>().deallocate(p, 512)
但G2.9里的容器使用的其实是另一个更好的分配器alloc
,能够减少malloc
的次数。
然而,G4.9默认使用的又变成了std::allocator
,设计跟VC、BC类似。同时,G4.9所附的标准库,有许多extention allocators
,其中__pool_alloc
就是G2.9的alloc
。
二、containers和iterators
目标:
(1)了解每种容器内部是如何实现的。
(2)了解每种容器的迭代器是如何移动的。
下图中的缩排表示“基层与衍生层”的关系。所谓衍生,并非继承而是复合。
只要是号称是连续空间的容器,都有operator[]
操作
1、list
list
是一个双向链表,每个结点有两个pointer
和一个data
。因为list
内存空间不连续,所以它的iterator
必须得是一个类,才能重载++
运算符。
Iterator
必须为algorithm
提供5种associate types
:
1)iterator_category
;
2)value_type
;
3)difference_type
;
4)reference
;
5)pointer
。
当iterator
是指针类型时,iterator
无法直接回答algorithm
上述的五个问题,因此引入一个中间层iterator traits
,再偏特化就能代替iterator
回答algorithm
的五个问题。
2、vector
vector
内有三个指针:start
、finish
和end_of_storage
。vector
的内存增长是两倍增长。
因为vector
内存空间连续,所以它的iterator
就是一个指向vector
元素的指针。
3、array
array
不能扩充,定义变量时需要指定大小。
4、forward_list
5、deque
deque
分段连续,为了维持连续的假象,当iterator
走到一个buffer
的末端时要能力跳到下一个buffer
的起始点。
6、rb_tree
红黑树是一种自平衡二叉查找树,内有iterator
,一直进行++iterator
操作会得到一个有序序列。
不能通过iterator
修改树结点值,因为修改后树可能就不是有序的,且红黑树是map
和set
的底层实现,而map
的键值是不能被修改的。
实现用例:
7、set/multiset
set
的大部分操作都是由其内含的红黑树完成的,set
里的iterator
是红黑树的const_iterator
(不能修改值)。
8、map/multimap
map
以红黑树为底层结构,因此也有元素自动排序的特性,排序的依据是key
。
map
元素的key
必须独一无二,因此其insert()
用的是rb_tree
的insert_unique()
。
multimap
元素的key
可以重复,因此其insert()
用的是rb_tree
的insert_equal()
。
map
独有一个operator[]
,可以做插入操作。
9、hashtable
可以根据hashtable iterators
改变元素的data
,但不能改变元素的key
(因为hashtable
根据key
实现严谨的元素排列)。
10、unordered
unordered_set
unordered_multiset
unordered_map
unordered_multimap
三、algorithms
Algorithms
看不见Containers
,对其一无所知,所以它所需要的一切信息都必须从Iterators
取得,而Iterators
(由Containers
供应)必须能够回答Algorithm
的所有提问,才能搭配该Algorithm
的所有操作。
//五种iterator category
struct input_iterator_tag{
};
struct output_iterator_tag{
};
struct forward_iterator_tag:public input_iterator_tag{
};
struct bidirectional_iterator_tag:public forward_iterator_tag{
};
struct random_access_iterator_tag:public bidirectional_iterator_tag{
};
算法需要知道迭代器的种类,好根据不同的类别采用不同的方法对迭代器进行操作,以提高程序效率。
1、accumulate
template <class InputIterator, class T, class BinaryOperation>
T accumulate(InputIterator first, InputIterator last, T init, BinaryOperation binary_op){
for(;first != last;++first){
// 传进来的binary_op只要能进行()操作就可以(意味着函数,仿函数等都可以)。
init = binary_op(init, *first);
}
return init;
}
2、for_each
template <class