为什么用STL
STL标准模板库(Standard Template Library)是每位C++都无法回避的库,但是有点复杂,如果你仅想快速会用,就是快速掌握80%的常用功能,这个文章值得你阅读,首先看下为什么要用STL:
未来代码的维护者学习你的版本的设计是否容易?
你的版本有多大可能性适用于 10 年之后的一个新平台?
你的版本有多大可能性适用于未来的应用?
你的版本有多大可能性能与用标准库编写的代码互操作?
你投入到优化和测试中的精力有多大可能性能与设计和实现标准库的投入相提并论?
STL框架
STL六大组件包括容器(container)、分配器(allocator)、算法(algorithm)、迭代器(iterator)、适配器(adapter)和仿函数(functor).我们常用的是容器与迭代器,把这两部分掌握,可以应付大部分的任务.
容器(containers)部分,STL的一个重要组成部分,涵盖了许多数据结构,比如前面曾经提到的链表,还有:vector(类似于大小可动态增加的数组)、queue(队列)、stack(堆栈)……。string也可以看作是一个容器,适用于容器的方法同样也适用于string。
迭代器(iterators)部分,STL的一个重要组成部分,如果没有迭代器的撮合,容器和算法便无法结合的如此完美。事实上,每个容器都有自己的迭代器,只有容器自己才知道如何访问自己的元素。它有点像指针,算法通过迭代器来定位和操控容器中的元素。
容器
STL容器大体分为序列容器,关联容器和无序容器.看如下图:
Vector:模塑出一个动态数组.是有序的集群.
Deques:也是动态数组,只是头尾两端都可以插入删除.
List是使用双向链表管理元素.
Set/Multiset:根据特定的排序准则,自动将元素排序.Multiset允许重复,Set不允许
Map/Multimap将键值/实值对当作元素,进行管理.它可根据key的排序准则自动将元素排序.multimaps允许重复,maps不允许,
至于每种容器的能力差异请参考<C++标准程序库>表6.33
容器的函数比对表
Vector | Maps及 Multimaps | Deques | List | Sets Multisets | ||
构造,拷贝和解构 | ||||||
c | 产生一个空的 | V | V | V | V | V |
c(op) | 以op排序准则 | X | V | X | X | V |
c1(c2) | 产生c2副本 | V | V | V | V | V |
c(n) | 产生n个元素,每个元素以默认构造初始化 | V | X | V | V | X |
c(n,elem) | 产生nge元素,每个元素都是elem副本 | V | X | V | V | X |
c(beg,end) | 以区间内的元素产生 | V | V | V | V | V |
c(beg,end,op) | 以op排序,利用区间内元素产生 | X | V | X | X | V |
非变动性操作 | ||||||
c.size() | 返回当前的元素数量 | V | V | V | V | V |
c.empty() | 等同于size()==0 | V | V | V | V | V |
c.max_ size() | 返回可容纳的元素最大数量 | V | V | V | V | V |
capacity() | 返回重新分配空间所能容纳的元素 最大数量 | V | X | X | X | X |
reserve() | 如果容量不足,扩大值 | V | X | X | X | X |
c1 c2 比大小 | V | V | V | V | V | |
赋值 | ||||||
c1 = c2 | 将c2的全部元素赋值给c1 | V | V | V | V | V |
c.assign (n,elem) | 复制n个elem,赋值给c | V | X | V | V | X |
c.assign (beg,end) | 将区间内的元素赋值给c | V | X | V | V | X |
c1.swap (c2) | 将c1和c2元素互换 | V | V | V | V | V |
swap (c1,c2) | 同上,此为全局变量 | V | V | V | V | V |
元素存取 | ||||||
c.at(idx) | 返回索引idx所表示的元素 | V | p->first | V | X | X |
c[idx] | 返回索引idx所表示的元素, 无范围检查 | V | p->second | V | X | X |
c.front() | 返回第一个元素, 不检查第一个元素是否存在 | V | X | V | V | X |
c.back() | 返回最后一个元素, 不检查最后一个元素是否存在 | V | X | V | V | X |
迭代器相关函数 | ||||||
c.begin() | 返回一个随机存取迭代器, 指向第一个元素 | V | V | V | V | V |
c.end() | 返回一个随机存取迭代器, 指向最后最后元素的下一个位置 | V | V | V | V | V |
c.rbegin() | 返回一个逆向迭代器, 指向你想迭代器的第一个元素 | V | V | V | V | V |
c.rend() | 返回一个你想迭代器,指向逆向迭代器 的最后元素的的下一个位置 | V | V | V | V | V |
insert和remove元素 | ||||||
c.insert() | 插入一个元素副本, map:c[key]=value 也可以实现插入元素 | V | V | V | V | V |
c.push_ back(elem) | 在尾部添加一个elem副本 | V | X | V | V | X |
c.pop_ back() | 移除最后一个元素(但不回传) | V | X | V | V | X |
c.push_ front(elem) | 在头部插入elem的一个副本 | X | X | V | V | X |
c.pop_ front() | 移除头部元素 | X | X | V | V | X |
c.erase (pos) | 移除pos位置或区间所有元素 | V | V | V | V | V |
c.resize (num) | 将元素数量改为num | V | X | V | V | |
c.clear() | 移除所有元素 | V | V | V | V | V |
c.remove (val) | 移除所有其值为val的元素 | X | X | X | V | |
c.remove _if(op) | 移除所有"造成op(elem)结果为true" 的元素 | X | X | X | V | |
特殊的搜寻动作 | ||||||
count(key) | 返回"键值等于key"的元素个数 | X | V | X | X | V |
find(key) | 返回"键值等于key"的第一个元素 找不到返回end() | X | V | X | X | V |
lower_bound (key) | 返回"键值为key"之元素的第一个可安插 位置,也就是"键值>=key"的第一个元素位置 | X | V | X | X | V |
uper_bound (key) | 返回"键值为key"之元素的最后一个可安插 位置,就是"键值>=可以"的第一个元素位置 | X | V | X | X | V |
equal_range (key) | 返回"键值为key之元素的第一个可安插 位置和最后一个可安插位置, 就是"键值==key"的元素区间 | X | V | X | X | V |
Splice 函数 | ||||||
c.unique() | 如果存在若干相邻而数值相等的元素, 就移除重复元素,只留下一个 | X | X | X | V | X |
c1.splice (pos,c2) | 将c2内的所有元素转移到c1之内, 迭代器pos之前 | X | X | X | V | X |
c.sort() | 以operator<为原则,对所有元素排序 | X | X | X | V | X |
c1.merge (c2,op) | 假设c1和c2容器都包含op()原则下的已序元素,将c2的全部元素转移到c1, 并保证合并后的list仍未已序 | X | X | X | V | X |
c.reverse() | 将所有元素反序 | X | X | X | V | X |
类模板实例化
数据的类型也可以通过参数来传递,在函数定义时可以不指明具体的数据类型,当函数 调用时,编译器根据传入的实参自动推断数据类型。——这就是类型的参数化(把类型 定义为参数),
这就是类模板的定义
template <class Key,
class Type,
class Traits = less<Key>,
class Allocator=allocator<pair <const Key, Type>>>
class map;
map模板实例化
std::map < int , int > m_pSetValue;
第一个int就是对key的实例化,第二个int就是对Type的实例化.
Pair结构
一种结构,该结构提供了将两个对象视为单个对象的的功能。
make_pair()是一种可用来构造 pair
类型对象的模板函数,其中,组件类型将根据作为参数传递的数据类型自动进行选择。函数原型:
template <class T, class U>
pair<T, U> make_pair(T& Val1, U& Val2);
pair<T, U> make_pair(T& Val1, U&& Val2);
pair<T, U> make_pair(T&& Val1, U& Val2);
pair<T, U> make_pair(T&& Val1, U&& Val2);
参数
Val1
用于初始化第一个 pair 元素的值。
Val2
用于初始化第二个 pair 元素的值。
返回值
所构造的配对对象:pair<T,U>(Val1, Val2)
make_pair 的优势之一在于要存储的对象类型由编译器自动确定,而不必显式指定.
以下为pair例程
#include <utility>
#include <map>
#include <iomanip>
#include <iostream>
int main( )
{
using namespace std;
pair <int, double> p1 ( 10, 1.1e-2 );//constexpr pair(const T1& Val1,const T2& Val2);
pair <int, double> p2;//constexpr pair();
p2 = make_pair ( 10, 2.22e-1 );//类型编译器自动确定
// Making a copy of a pair
pair <int, double> p3 ( p1 );//pair(const pair&)
cout.precision ( 3 );
cout << "The pair p1 is: ( " << p1.first << ", "
<< p1.second << " )." << endl;
cout << "The pair p2 is: ( " << p2.first << ", "
<< p2.second << " )." << endl;
cout << "The pair p3 is: ( " << p3.first << ", "
<< p3.second << " )." << endl;
}
容器的实用例子
main()
{
std::vector<unsigned char> Buffer;// vector实例化
unsigned char *data = "hello STL";
for (int i = 0; i < strlen(data); i++) {
//先添加到缓冲区中
Buffer.push_back(data[i]);//vector尾部添加一个字符元素
}
std::string Mystring(Buffer.begin(), Buffer.end());//用这个构造函数template <class InputIterator> basic_string(InputIterator first,InputIterator last);
Buffer.clear();
printf("%s",Mystring);
delete[] data;
data = NULL;
}
main()
{
std::map < int , int > m_pSetValue;//创建一个map容器,
m_pSetValue[1] = 10;//通过[]直接元素存取
std::map < int, int > ::iterator it = m_pSetValue.begin();
int addr = it->first;
int value = it->second;
m_pSetValue.erase(it);
return 0;
}
main()
{
map<pair<int,int>, Info1*>::iterator it1;//创建迭代器.
for (it1 = Map1.begin(); it1 != Map1.end(); it1++)//遍历整个Map1
{
pair<int, int> pairIndex = make_pair(it1->first, it1->second);
map<pair<int, int>, Info*> ::iterator it = InfoMap.find(pairIndex);
Info *pInfo = NULL;
if (it != InfoMap.end())//找到了
{
pInfo = it->second;//把
}
else//没找到
{
pInfo = new LogInfo;
pInfo->value1= it1->first;
pInfo->value2= it1->second;
InfoMap[pairIndex] = pInfo;//map的[]操作
}
pInfo->value3 = 6;
}
}