STL提供了一组表示容器、迭代器、函数对象和算法的模板。
容器是一个与数组类似的单元。可以存储若干个值。STL容器是同质的,即存储的值的类型相同;
算法是完成特定任务(如对数组进行排序或在链表中查找特定值)的方法;
迭代器能够用来遍历容器的对象,与能够遍历数组的指针类似,是广义指针;
函数对象是类似于函数的对象,可以是类对象或函数指针(包括函数名,因为函数名被用作指针)。
STL使得能够构造各种容器(包括数组、队列和链表)和执行各种操作(包括搜索、排序和随机排列)。
STL不是面向对象的编程,而是一种不同的编程模式——泛型编程。
模板类vector
#include <vector>
using namespace std;
vector<int> rating(5);
由于运算符[]被重载,因此创建vector对象后,可使用通常的数组表示法来访问各个元素。
分配器
与string类相似,各种STL容器模板都接受一个可选的模板参数。该参数指定使用哪个分配器对象来管理内存。例如:
template <class T, class Allocator = allocator<T>>
class vector { ... }
如果省略该模板参数,则容器模板将默认使用allocator类。这个类使用new和delete。
可对矢量执行的操作
所有的STL容器都提供了一些基本方法,其中包括:
size():返回容器中元素数目;
swap():交换两个容器的内容;
begin():返回一个指向容器中第一个元素的迭代器;
end():返回一个表示超过容器尾的迭代器;
通过将指针广义化为迭代器,让stl能够为各种不同的容器类提供统一的接口。每个容器类都定义了一个合适的迭代器,该迭代器的类型是一个名为iterator的typedef,其作用域为整个类。
vector<double>::iterator pd;
vector<double> scores;
//迭代器pd的行为就像指针一样
pd = scores.begin();
*pd = 22.9;
++pd;
C++11的自动类型推断可以简化上面的代码
vector<double> scores;
auto pd = scores.begin();
*pd = 22.9;
++pd;
push_back():将元素添加到矢量末尾;
erase():删除矢量中给定区间的元素。它接受两个迭代器参数;这些参数定义了要删除的区间。
insert():它接受2个迭代器参数,第一个参数指定来了新元素的插入位置,第二个和第三个迭代器参数定义了被插入区间,该区间通常是另一个容器对象的一部分。
对矢量可执行的其它操作
我们通常对数组执行很多操作,如搜索、排序、随机排序。矢量模板没有包含这些常见的操作,没有! STL从更广泛的角度定义看非成员函数来执行这些操作。即不是为每个容器类定义find()成员函数。而是定义一个适用于所有容器的非成员函数find()。这种设计理念省去了大量重复的工作。
另一方面,即使有执行相同任务的非成员函数,STL有时也会定义一个成员函数。这是因为对有些操作来说,类特定算法的效率比通用算法高。因此vector的成员函数swap的效率比非成员函数swap高,但非成员函数能交换两个类型不同的容器的内容。
下面介绍3个具有代表性的STL函数:for_each()、random_shuffle()和sort()。
• for_each()函数可以用于很多容器类,它接受3个参数,前两个定义容器中区间的迭代器,最后一个是指向函数的指针。for_each()将被指向的函数应用于容器区间中的各个元素。被指向的函数不能修改容器元素的值。可以用for_each()来替换for循环。
vector<Review>::iterator pr;
for (pr = books.begin(); pr != books.end(), pr++)
ShowReview(*pr);
//for_each()替换for。可避免显式使用迭代器变量
for_each(books.begin(), books.end(), ShowReview);
• random_shuffle()函数接受两个指定区间的迭代器参数,并随机排列该区间中的元素。
random_shuffle(books.begin(), books.end())
该函数与可用于任何类的for_each不同,该函数要求容器允许随机访问。vector类可以。
• sort()函数也要求容器支持随机访问。该函数有两个版本,第一个版本接受两个定义区间的迭代器参数,并使用为存储在容器中的类型元素定义的<运算符,对区间中的元素进行操作>,例如下面的示例按升序排序时,使用内置的 < 运算符对值进行比较:
vector<int> coolstuff;
...
sort(coolstuff.begin(), coolstuff.end())
如果类型是用户定义的对象,则需要使用sort(),必须定义能够处理该类型对象的operator<()函数。
另外一个版本的sort(),它接受3个参数,前两个参数也是指定区间的迭代器,最后一个参数是指向要使用的函数的指针(函数对象),而不是用于比较operator<()。
bool WorseThan(const Review & r1, const Review & r2)
{
if (r1.rating < r2.rating)
return true;
else
return false;
}
sort(books.begin(), books.end(), WorseThan);
基于范围的for循环(C++11)
基于范围的for循环是为用于STL而设计的。
double prices[5] = {4.99, 10.99, 6.85, 7.89, 8.46};
for (double x : prices)
cout << x << endl;
在这种for循环中,括号内的代码声明一个类型与容器存储的内容相同的变量,然后指出了容器的名称。接下来,循环体使用指定的变量依次访问容器的每个元素。
for_each(books.begin(), books.end(), ShowReview);
//用下述基于范围的for循环替换
for (auto x : books) ShowReview(x);
编译器将推断出x的类型为Review,而循环将依次将books中的每个Review对象传递给ShowReview()。
不同于for_each(),基于范围的for循环可修改容器的内容,指定一个引用参数。
下一节——泛型编程。