标准库源代码在计算机中的分布
本机所用开发环境为visual studio 2013(包含了VC),其中C/C++所用的工具库包含在VC里面。
OOP(面向对象编程)VS GP(泛型编程)
- OOP企图将dates和methods关联在一起
- list不能使用全局的sort()排序,因为全局sort()需要的是随机访问迭代器,例如first+(last-first)/2这样的只有RandomAccessIterator才能如此操作,而list因为内存模型的原因,不是连续空间,不能有iterator+5这种操作,所以它不能提供这种迭代器。
- vector、deque等容器都提供RandomAccessIterator。
template
class list{
...
void sort();
}
- GP却是将datas和methods分开来,这样做的好处是:
- Containers和Algorithms团队可各自闭门造车,其间以Iterator沟通即可。
- Algorithms通过Iterators确定操作范围,并通过Iterators取用Container元素。
//Data Structures(Containers)
template
class vector{
...
};
//Alorithms
template
inline void
sort(_RandomAccessIterator _first,_RandomAccessIterator _last)
{
...
}
- 所有algorithms,其内最终涉及元素本身的操作,无非就是比大小
bool strLonger(const string& s1,const string& s2) {return s1.size() < s2.size();}
cout<<"max of zoo and hello:"< //函数1
inline const T& max(const T& a,const T& b){
return a //函数2
inline const T& max(const T& a,const T& b,Compare comp){
return comp(a,b)?b:a;
}
分配器
- operator new()追究到底最后调用的是C函数库中malloc()函数
- VC6+、BC++、GCC2.9的allocator都只是以::operator new和::operator delete完成allocate()和deallocate(),没有任何特殊设计。
//VC6使用allocator,分配512ints
int* p=allocator().allocate(512,(int*)0);
allocator().deallocate(p,512);
//BC5使用allocator,分配512ints
int* p=allocator().allocate(512);
allocator().deallocate(p,512);
//G2.9使用allocator,分配512bytes
void* p=alloc::allocate(512); //也可以alloc().allocate(512);
alloc::deallocate(p,512);
-
G2.9所附的标准库,其allocator实现如下:
-
其中alloc的实现如下图(
):
- G4.9STL对allocator的使用:
template>
class vector :protected _Vector_base<_Tp , _Alloc>
{
...
}
-
G4.9所附的标准库,其allocator实现如下:
- 相比G2.9,G4.9对于allocator的写法因为大量应用了类的继承、复合,使得观察者在理解allocator的实现上增加不少难度!
容器之间的实现关系与分类
- 本图以缩排形式表达“基层与衍生层”的关系。这里所谓衍生,并非继承而是复合。
-
在C++中,slist名为forward_list,hash_set,hash_map名为unordered_set,unordered_map,hash_multiset,hash_multimap名为unordered_multiset,unordered_multimap;且新添array。
迭代器的设计原则和Iterator Traits的作用与设计
Iterators必须有能力回答algorithms的五个问题,也就是说Iterators必须提供五种associated types。
为了分离class Iterators和non-class Iterators,就产生了Iterator traits,并且可以通过偏特化实现。
- 还有其他各式各样的traits
- type traits ----------------<.../C++/type_traits>
- iterator traits-------------<.../C++/bits/stl_iterator.h>
- char traits----------------<.../C++/bits/char_traits.h>
- allocator traits-----------<.../C++/bits/alloc_traits.h>
- pointer traits-------------<.../C++/bits/ptr_traits.h>
- array traits---------------<.../C++/bits/array>
深度探索list
参考链接【深度探索STL】详解 list
list 和vector 是两个最常用的容器(序列式容器)。二者最显著的区别自然就是vector是连续线性空间,list则是不连续线性空间,相比于vector(动态数组),它的好处是每次插入和删除一个元素,只需配置或释放一个元素空间,对于任何位置的元素插入或元素移除,list永远是常数时间。尺有所长,寸有所短,list 寻址某一元素也没有vector(常数时间)方便。
- list 的迭代器
- 因为链表节点在储存空间中不一定是连续存在的,自然也就不能像vector一样用普通指针作为迭代器。list迭代器必须有能力指向list的节点,并有能力正确的递增。递减。取值、成员存取等操作。这是作为任何一个容器的迭代器必须具备的。对于非连续空间的递增,递减等操作自然是针对该容器的属性来的,就list而言,则是指向上一个节点,下一个节点,以及获取指定节点。
STL list是一个双向链表,迭代器必须具备前移,后移的能力,所以list提供的是bidirectional iterator (双向一个个移动)。关于迭代器的分类,参见STL迭代器。vector是随机迭代器类型(random access iterator),这也是符合vector 可随机存取的能力。
- 因为链表节点在储存空间中不一定是连续存在的,自然也就不能像vector一样用普通指针作为迭代器。list迭代器必须有能力指向list的节点,并有能力正确的递增。递减。取值、成员存取等操作。这是作为任何一个容器的迭代器必须具备的。对于非连续空间的递增,递减等操作自然是针对该容器的属性来的,就list而言,则是指向上一个节点,下一个节点,以及获取指定节点。
struct _List_iterator_base {
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef bidirectional_iterator_tag iterator_category;
_List_node_base* _M_node;
//构造函数
_List_iterator_base(_List_node_base* __x) : _M_node(__x) {}
_List_iterator_base() {}
//增加和减少,就是指向上一个节点和下一个节点
void _M_incr() { _M_node = _M_node->_M_next; }
void _M_decr() { _M_node = _M_node->_M_prev; }
//运算符重载
bool operator==(const _List_iterator_base& __x) const {
return _M_node == __x._M_node;
}
bool operator!=(const _List_iterator_base& __x) const {
return _M_node != __x._M_node;
}
};
template
struct _List_iterator : public _List_iterator_base {
typedef _List_iterator<_Tp, _Tp&, _Tp*> iterator;
typedef _List_iterator<_Tp, const _Tp&, const _Tp*> const_iterator;
typedef _List_iterator<_Tp, _Ref, _Ptr> _Self;
typedef _Tp value_type;
typedef _Ptr pointer;
typedef _Ref reference;
typedef _List_node<_Tp> _Node;
//下面是子类指针赋值给父类指针,is-a原则(反过来不行)
_List_iterator(_Node* __x) : _List_iterator_base(__x) {}
_List_iterator() {}
_List_iterator(const iterator& __x) : _List_iterator_base(__x._M_node) {}
//对迭代器取值,获取节点的数据
reference operator*() const { return ((_Node*)_M_node)->_M_data; }
//对迭代器的成员存取,返回的是地址
#ifndef __SGI_STL_NO_ARROW_OPERATOR
pointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */
//前缀和后缀++和--自增自减符重载
_Self& operator++() {
this->_M_incr();
return *this;//返回引用,可链式操作
}
_Self operator++(int) {
_Self __tmp = *this;
this->_M_incr();
return __tmp;//返回变量,不可链式操作
}
_Self& operator--() {
this->_M_decr();
return *this;
}
_Self operator--(int) {
_Self __tmp = *this;
this->_M_decr();
return __tmp;
}
};
深度探索vector
vector 将其元素置于一个动态数组中加以管理,与 array 非常类似,两者的唯一差别在于空间运用的灵活性,array 是静态空间,一旦配置了就不能更改,当需要容纳更多的元素时(此时已越界),需要重新手动配置更大的 array 空间,然后重新置入数据。而 vector 是动态空间,在同样的情况下,随着元素的加入,它的内部机制会自行扩充空间以容纳新元素。vector 同 array 一样可以很方便的通过索引值直接存取任何一个元素,在数组的尾端追加或移除元素均非常快速(当追加元素超出原有分配空间时,vector需要重新分配空间),但在其中间或头部插入移除元素就比较费时,需要移动安插点之后的所有元素以保持原来的相对位置。
深度探索array&forward_list
与list和vector的iterator类似,有一种iterator traits用以分类class Iterators和non-class Iterators。