1. STL标准库
STL提供了一组表示容器,迭代器,函数对象和算法的模板。STL不是面线对象的变成,而是一种不同的编程模式——泛型编程(generic programming)。面向对象编程关注的是编程的数据方面,而泛型编程关注的是算法,他们之间的共同点是抽象和创建可重用代码,但理念绝不相同。
容器是和数组类似的单元,可以存储若干值,存储的类型要相同;
迭代器能够用来遍历容器中的对象,与指针类似,是广义指针;
函数对象是类似于函数的对象,可以是类对象或函数指针(包括函数名,因为函数名被用作指针);
算法是完成特定任务的方法(如对数组进行排序或在链表中查找特定值)。
1.1 模板类vector
可以在运行阶段设置vector的长度,可以在中间插入数据。基本上它是使用new创建动态数组的替代品。实际上vector类确实使用new和delete来管理内存,不过这些工作是自动完成的。
首先,要使用vector对象,必须包含头文件vector。其次,vector包含在名称空间std中,因此可以使用using
编译指令、using
声明或std::vector
。第三,模板使用不同的语法来指出他存储的数据类型。第四,vector使用不同的语法来指定元素数。
#include <vector>
using namespace std;
vector<int> vi(4); //创建一个长度为4的整型vector对象
int n;
cin >> n;
vector<double> vd(n); //创建一个长度为n的双精度vector对象
从这里可以看出vector与普通数组除了定义方式不同之外,它的长度可设置为整型常量或者变量。
下面介绍vector类的方法应用:
vector<double> scores; //creat an empty vector
double temp = 1;
scores.push_back(temp); //将temp变量的值添加到scores末尾
scores.erase(scores.begin(),scores.begin()+2); //删除指定区间中的内容
vector<double> nums;
//begin()指向vector第一个元素,end()指向vector最后一个元素的后面一个元素,类似字符串最后的空字符;
//insert()第一个参数为被插入的初始位置,第二、三参数为插入的内容区间
nums.insert(nums.begin(),scores.begin(),scores.end()-1);
1.2 模板类array
vector可以使用在对象长度不固定的场景中,如果需要对象长度固定,使用array类是一个很好的选择。array与vector创建语法稍有不同。
#include <array>
using namespace std;
array<int, 5> ai; //创建一个长度为5的整型array对象
array<double, 4> ad = {1.2, 2.1, 4.3, 5.6};
与vector不同的是,array的长度必须给定,且不能是变量。
1.3 比较数组、vector对象和array对象
首先,数组、vector对象和array对象后可以用标准的数组表示法来访问各个元素。其次,array对象和数组存储在相同的内存区域(即栈)中,而vector对象存储在自由存储区或堆中。第三,可以将array对象直接赋给另一个array对象;对于数组,必须逐元素赋值数据。
a1[-2] = 20.3;
中-2
是什么意思呢?它与下面的代码一致:
*(a1-2) = 20.3;
其含义是找到a1指向的地址,向前移动两个typename元素,并将20.3存储到目的地。这里,可能会出现超界错误,C语言和C++都不检查这种错误,若想避免,写代码时需要多留心,还可以通过其他成员函数来确定边界,这里不做讨论。
1.4 为何使用迭代器
理解迭代器是理解STL的关键所在。模板使得算法独立于存储的数据类型,而迭代器使得算法独立于使用的容器类型。比如我想建立一个find()
函数,在double类型下和链表类型下的find()
函数是不同的,所以不同的数据类型想完成相同功能都需要重新再写一个函数,如何解决这个问题呢?这里就需要用到迭代器了。
什么是迭代器?它是一个广义指针。事实上,它可以是一个指针,也可以是一个可对其执行类似指针的操作。通过将指针广义化为迭代器,让STL能够为各种不同的容器类提供统一的接口。每个容器类都定义了一个合适的迭代器,作用域为整个类,定义如:vector<double>:: iterator pd;
可以将迭代器看作指针理解,例如
vector<double>:: iterator pd;
vector<double> scores;
pd = scores.begin(); //pd指向scores第一个元素
*pd = 22.3; //设置scores第一个元素为22.3
++pd; //pd指向下一个元素
根据C++11的auto类型,vector<double>:: iterator pd = scores.begin();
可以直接写为auto pd = scores.begin();
还可用下面代码实现scores的遍历:
for (auto pd = scores.begin();pd != scores.end();pd++)
{
cout<< *pd <<endl;
}
1.5 函数对象
很多STL算法都是用函数对象——也叫函数符。