C++ STL
一、体系结构
1.初始
-
头文件
c++标准库不包括.h,#include;c旧库需要包括.h,#include<stdio.h>;c新库在旧库前面加c,不需要包含.h,#include 。
旧头文件不被封装在std命名空间中。 -
网站资源
www.cplusplus.com
cppreference.com
gcc.gnu.org -
书籍

2.STL体系结构
- 部件
六大部件:容器、分配器、迭代器、适配器、算法、仿函式
容器用于管理内存。
分配器用于支持容器的内存管理。
除了容器模板类本身的操作之外,其他操作被独立出来作为算法;可见则不是面向对象编程,而是模板编程。
迭代器是泛化的指针,用于协助算法操作容器。
仿函数用于对类进行函数操作。
适配器可以转换容器、仿函数、迭代器。

- 复杂度
没有一种容器或者算法是最优的,而是根据需求选择。

- 前闭后开区间
begin()指向第一个元素,end()指向最后一个元素的下一个位置。无论是否是连续容器。因此,遍历容器可以:
Container<T> c;
...
Container<T>::iterator ite = c.begin();
for(;ite!=c.end();++ite)
...
除此之外,可以使用范围for循环。其中遍历对象是迭代器。
std::vector<int> vec;
...
for(auto elem:vec){ std::cout<<elem<<std::endl; }
for(auto& elem:vec){ elem*=2; }
3.容器分类与结构
序列容器、关联容器(key-value,适合快速查找)、不定序容器(一种关联容器,使用hash table实现)

序列容器
- array
将array包装成了class,无法扩充。
array<long,Asize>c;
for(long i=0;i!=Asize;++i) c[i]=rand();
coud<<c.size()<<" "<<c.front()<<" "<<c.back()<<" "<<c.data();//尺寸、第一个元素、最后一个元素、地址
qsort(c.data(),Asize,sizeof(long),compareLongs);
long* pItem = (long*)bsearch(&tarhet,(c.data(),Asize,sizeof(long)));
- vector
可以向后扩展与删除。
vector<string>c;
char buf[10];
for(long i=0;i!=value;++i)
{
try{
c.push_back(string(buf));
}
catch(exception& p)
{
abort();//退出程序
}
}
cout<<c.size()<<" "<<c.front()<<" "<<c.back()<<" "<<c.data()<<" "<<c.capacity();
auto pItem = ::find(c.begin(),c.end(),target);cout<<*pItem;
sort(c.begin(),c.end());
string* pItem = (string*)bsearch(&target,(c.data()),c.size(),sizeof(string));
- list
不连续空间,使用指针的双向环状链表。
list<string>c;
char buf[10];
for(long i=0;i!=value;++i)
{
try{
c.push_back(string(buf));
}
catch(exception& p)
{
abort();//退出程序
}
}
cout<<c.size()<<" "<<c.front()<<" "<<c.back()<<" "<<c.max_size();
auto pItem = ::find(c.begin(),c.end(),target);
c.sort();//当容器自身提供sort时要比全局sort更快。
- forward-list
不连续空间,使用指针的单向链表。考虑到指针空间,单向链表比双向链表更节省内存。
forward_list<string>c;
char buf[10];
for(long i=0;i!=value;++i)
{
try{
c.push_front(string(buf));//需要使用push_front(),而非push_back()
}
catch(exception& p)
{
abort();//退出程序
}
}
cout<<c.front()<<" "<<c.max_size();//没有back、size
auto pItem = ::find(c.begin(),c.end(),target);
c.sort();//当容器自身提供sort时要比全局sort更快。
- slist
#include<ext\slist>
__gnu_cxx::slist<string>c;
char buf[10];
for(long i=0;i!=value;++i)
{
try{
c.push_front(string(buf));//需要使用push_front(),而非push_back()
}
catch(exception& p)
{
abort();//退出程序
}
}
cout<<c.front()<<" "<<c.max_size();//没有back、size
auto pItem = ::find(c.begin(),c.end(),target);
c.sort();//当容器自身提供sort时要比全局sort更快。
- deque
两端可进可出。
分段连续,段内部连续,段间不连续,操作符重载++使得使用者感觉是连续的。如果空间不够,当push_back,会在后面分配新的buffer,当push_front,会在前面分配新的buffer。因为是以buffer分配的,所以会比vector按倍数分配更节省空间,当然比list、forward_list、slist占用空间更多,但是查找效率更高。

deque<string>c;
char buf[10];
for(long i=0;i!=value;++i)
{
try{
c.push_back(string(buf));
}
catch(exception& p)
{
abort();//退出程序
}
}
cout<<c.size()<<" "<<c.front()<<" "<<c.back()<<" "<<c.max_size();
auto pItem = ::find(c.begin(),c.end(),target);cout<<*pItem;
::sort(c.begin(),c.end());
- stack
先进先出。使用deque实现。可以看作容器的adapter。不提供iterator,避免破坏容器先进后出。
stack<string>c;
char buf[10];
for(long i=0;i!=value;++i)
{
try{
c.push(string(buf));
}
catch(exception& p)
{
abort();//退出程序
}
}
cout<<c.size()<<" "<<c.top()<<" "<<c.back();
c.pop();
- queue
先进先出。使用deque实现。可以看作容器的adapter。不提供iterator,避免破坏容器后进先出。
queue<string>c;
char buf[10];
for(long i=0;i!=value;++i)
{
try{
c.push(string(buf));
}
catch(exception& p)
{
abort();//退出程序
}
}
cout<<c.size()<<" "<<c.front()<<" "<<c.back()<<" "<<c.back();
c.pop();
关联容器
使用红黑树实现。
- set/multiset
key就是value;multiset表示key可重复。
multiset<string>c;
char buf[10];
for(long i=0;i!=value;++i)
{
try{
c.insert(string(buf));//插入到树中合适的位置
}
catch(exception& p)
{
abort();//退出程序
}
}
cout<<c.size()<<" "<<c.max_size();
auto pItem = ::find(c.begin(),c.end(),target);
auto pItem = c.find(target);//自我定义的更快
cout<<*pItem;
set<string>c;
char buf[10];
for(long i=0;i!=value;++i)
{
try{
c.insert(string(buf));//插入到树中合适的位置
}
catch(exception& p)
{
abort();//退出程序
}
}
cout<<c.size()<<" "<<c.max_size();
auto pItem = ::find(c.begin(),c.end(),target);
auto pItem = c.find(target);//自我定义的更快
cout<<*pItem;
- map/multimap
每个节点有key和value;multimap表示key可重复。
multimap<long, string>c;
char buf[10];
for(long i=0;i!=value;++i)
{
try{
c.insert(pair<long,string>(i,string(buf)));//插入到树中合适的位置,不可以使用[]插入
}
catch(exception& p)
{
abort();//退出程序
}
}
cout<<c.size()<<" "<<c.max_size();
auto pItem = ::find(c.begin(),c.end(),target);
auto pItem = c.find(target);//自我定义的更快
cout<<(*pItem).second;
map<long, string>c;
char buf[10];
for(long i=0;i!=value;++i)
{
try{
//c.insert(pair<long,string>(i,buf));//插入到树中合适的位置,可以使用[]插入
c[i]=string(buf);
}
catch(exception& p)
{
abort();//退出程序
}
}
cout<<c.size()<<" "<<c.max_size();
auto pItem = ::find(c.begin(),c.end(),target);
auto pItem = c.find(target);//自我定义的更快
cout<<(*pItem).second;
不定序容器
使用hash table实现。根据计算来决定元素放在表中的位置,如果发生碰撞则分开放,但是不够理想,而是以链表保存碰撞的元素。如果碰撞次数太多,链表就会很长,查找效率很低,此时会重新打散。

- unordered_multiset
unordered_multiset<string>c;
char buf[10];
for(long i=0;i!=value;++i)
{
try{
c.insert(string(buf));//插入到树中合适的位置
}
catch(exception& p)
{
abort();//退出程序
}
}
cout<<c.size()<<std::endl;
cout<<c.max_size()<<endl;
cout<<c.bucket_count()<<endl;//槽位数量,如果元素数量比篮子数量多,就会让篮子数量翻倍,然后打散元素重新分配,因此篮子数量一定比元素数量多
cout<<c.max_bucket_count()<<endl;
cout<<c.load_factor()<<endl;
cout<<c.max_load_factor()<<endl;//1不变
auto pItem = ::find(c.begin(),c.end(),target);
auto pItem = c.find(target);//自我定义的更快
cout<<*pItem;
- unordered_multimap
unordered_multimap<string>c;
char buf[10];
for(long i=0;i!=value;++i)
{
try{
c.insert(pair<long,string>(i,string(buf)));//插入到树中合适的位置
}
catch(exception& p)
{
abort();//退出程序
}
}
cout<<c.size()<<std::endl;
cout<<c.max_size()<<endl;
auto pItem = ::find(c.begin(),c.end(),target);
auto pItem = c.find(target);//自我定义的更快
cout<<*pItem;
- hash_set, hash_map, hash_multiset, hash_multimap是c++1.0不被采纳而被厂家实现的旧版本
4.分配器之测试
默认的是std::allocator<>,在memory中

其他分配器在ext扩展库中,不是标准库,其命名空间是__gnu_cxx。

应当用容器,而当有额外的空间分配需求时使用new或malloc,而不是使用分配器,因为delete或free不需要记住申请空间的大小。
二、内核分析
1.源代码分布
- VC++:...\include\
- GNU C++:...\4.9.2\include\c++\bits, ...\4.9.2\include\c++\ext
2.OOP与GP
GP将操作与数据分开,通过使用迭代器实现。
这就使得容器和算法团队可以各自做事,只要定义好接口。如下使用模板给出min的接口,而具体的算法实现通过操作符重载来完成。
template<class T>
inline const T& min(const T& a, const T& b){ return b<a?b:a; }
template<class T,class Compare>
inline const T& min(const T& a, const T& b, Compare comp){ return comp(a,b)?b:a; }
cout<<max("happy","test");//默认大小比较
bool strLonger(const string& s1, const string& s2){ return s1.size()<s2.size(); }
cout<<max("happy","test",strLonger);//自己实现大小比较
list将sort自我实现,这是因为全局sort进行了(first+last)/2操作,这只适用随机迭代器。
3. 技术基础
- 迭代器的指针操作符重载
- 类模板、函数模板、成员模板