STL提供了一组表示容器、迭代其、函数对象和算法的模板。容器是一个与数组类似的单元,可以存储若干个值。STL容器是同质的,即存储的值的类型相同;算法是完成特定任务(如对数组进行排序或在链表中查找特定值)的处方;迭代其能够用来遍历容器的对象,与能够便利数组的指针类似,是广义指针;函数对象是类似于函数的对象,可以使类对象或函数指针(包括函数名,因为函数名被用作指针)。STL使得能够构造各种容器(包括数组、队列和链表)和执行各种操作(包括搜索、排序和随机排列)。
Alex Stepanov和Meng Lee在Hewlett-Packard实验室开发了STL,并于1994年发布其实现。ISO/ANSI C++委员会投票同意将其作为C++标准的组成部分。STL不知面向对象的编程,而是一种不同的编程模式——泛型编程(generic programming)。

16.3.1 模板类vector
在计算中,矢量(vector)对应数组,而不是数学中的矢量。
vector类提供了与第14章valarray和ArrayTP以及第4章介绍的array类似的操作,即可以创建vector对象,将一个vector对象赋给另一个对象,使用[]运算符来访问vector元素。要使类称为通用的,应将它设计为模板类,STL正是这样做的——在头文件vector(以前为vector.h)中定义了一个vector模板。
要创建vector模板对象,可使用通常的<type>表示法来指出要使用的类型。另外,vector模板使用动态内存分配,因此可以用初始化来指出需要多少矢量:
#include <vector>
using namespace std;
vector<int> ratings(5); // a vector of 5 ints
int n;
cin >> n;
vector<double> scores(n);   // a vector of n doubles
由于运算符[]被重载,因此创建vector对象后,可以使用通常的数组表示法来访问各个元素:
ratings[0] = 9;
for (int i = 0; i < n; i ++)
    cout << scores[i] << endl;

/*-----------------------分配器---------------------
与string类相似,各种STL同期模板都接受一个可选的模板参数,该参数指定使用哪个分配器对象来管理内存。例如,vector模板的开头与下面类似:
template <class T, class Allocator = allocator<T> >
    class vector { ...
如果省略该模板参数的值,则容器模板将默认使用allocator<T>类。这个类使用new和delete。
--------------------------------------------------*/

16.3.2 可对矢量执行的操作
所有的STL容器都提供了一些基本方法,其中包括:
size()    —— 返回容器中元素数目
swap()    —— 交换量割绒其的内容
begin()    —— 返回一个指向容器中第一个元素的迭代器
end()    —— 返回一个表示超过容器尾的迭代器
迭代器:是一个广义指针。事实上,它可以是指针,也可以是一个可对其执行类似指针的操作——如解除引用(如operator*())和递增(如operator++())——的对象。通过将指针广义化为迭代其,让STL能够为各种不同的容器类(包括那些简单指针无法处理的类)提供统一的接口。每个容器类都定义了一个合适的迭代器,该迭代其的类型是一个名为iterator的typedef,其作用域为整个类。例如,要为vector的double类型规范声明一个迭代其,可以这样做:
vector<double>::iterator pd;    // pd an iterator
假设scores是一个vector<double>对象:
vector<double> scores;
则可以使用迭代其pd执行这样的操作:
pd = scores.begin();    // have pd point to the first element
*pd = 22.3;             // dereference pd and assign value to first element
++pd;                   // make pd point to the next element
可以看到,迭代器的行为就像指针。
还有一个C++11自动类型推断很有用的地方。例如,可以不这样做:
vector<double>::iterator pd = scores.begin();
而这样做:
auto pd = scores.begin();    // C++11 automatic type deduction
超过结尾(past-the-end)是一种迭代器,指向容器最后一个元素后面的哪个元素。这与C-风格字符串最后一个字符后面的空字符串类似,指示空字符是一个值,而“超过结尾”是一个指向元素的指针(迭代器)。end()成员函数标识超过结尾的位置。如果将迭代其设置为容器的第一个元素,并不断地递增,则最终它降到大容器结尾,从而遍历整个容器的内容。因此,如果scores和pd的定义与前面的示例中相同,则可以用下面的代码来显式容器的内容:
for (pd = scores.legin(); pd != scores.end(); pd ++)
    cout << *pd << endl;
所有容器都包含刚才讨论的那些方法。vector模板类也包含了一些只有某些STL容器才有的方法。push_back()是一个方便的方法,它将元素添加到矢量末尾。这样做时,它将负责内存管理,增加矢量的长度,使之呢狗狗容纳新的成员,这意味着可以编写这样的代码:
vector<double> scores;  // create an empty vector
double temp;
while (cin >> temp && temp >= 0)
    scores.push_back(temp);
cout << "You entered " << scores.size() << " scores.\n";
erase()方法删除矢量中给定区间的元素。它接受来那个哥迭代其参数,这些参数定义了要删除的区间。了解STL如何使用两个迭代其来定义区间至关重要。第一个迭代其指向区间的起始处,第二个迭代其位于区间终止除的后一个位置。例如,下述代码删除第一个和第二个元素,即删除begin()和begin()+1指向的元素(由于vector提供了随机访问功能,因此vector类迭代其定义了诸如begin()+2等操作):
scores.erase(scores.begin(), scores.begin() + 2);
如果it1和it2是迭代器,则STL文档使用[p1,p2)来表示p1到p2(不包括p2)的区间。
insert()方法的功能与erase()相反。它接受3个迭代其参数,第一个参数制定了新元素的插入位置,第二个和第三个迭代其参数定义了被插入区间,该区间通常是另一个容器对象的一部分。例如,下面的代码将矢量new_v中除第一个元素外的所有元素插入到old_v矢量的第一个元素前面:
vector<int> old_v;
vector<int> new_v;
...
old_v.insert(old_v.begin(), new_v.begin() + 1, new_v.end());
顺便说一下,对于这种情况,拥有超微元素是非常方便的,因为这使得在矢量尾部附加元素非常简单。下面的代码将新元素插入到old.end()前面,即矢量最后一个元素的后面。
old_v.insert(old_v.end(), new_v.begin() + 1, new_v.end());

16.3.3 对矢量可执行的其他操作
程序员通常要对数组指向很多操作,如搜索、排序、随机排序等。矢量模板类包含了执行这些常见操作的方法吗?答案是没有!STL从更广泛的角度定义了非成员(non-member)函数来执行这些操作,即不是为每个容器定义find()成员函数,而是定义了一个适用于所有容器类的非成员函数find()。这种设计理念省去了大量重复的工作。例如,假设有8个容器类,需要支持10中操作。如果每个类都有自己的成员函数,则需要定义80(8*10)个成员函数。但采用STL方式时,只需要定义10个非成员函数即可。在定义新的容器类时,只要遵循正确的指导思想,则它也可以使用已有的10个非成员函数来执行查找、排序等操作。
另一方面,即使有执行相同任务的非成员函数,STL有时也会定义一个成员函数。这时因为对有些操作来说,类特定算法的效率比通用算法高,因此,ector的成员函数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(books.begin(), books.end(), ShowReview);
这样可以避免显式地调用迭代其变量。
Random_suhffle()函数接受两个指定区间的迭代其参数,并随机排列该区间中的元素。例如,下面的语句随机排列books矢量中所有元素:
random_shuffle(books,begin(), books.end());
与可用于任何容器类的for_each不同,该函数要求容器类允许随机访问,vector类可以做到这一点。
sort()函数也要求容器支持随机访问。该函数有两个版本,第一个版本接受两个定义区间的迭代其参数,并使用为存储在容器中的类型元素定义的<运算符,对区间中的元素进行操作。例如,下面的语句按升序对coolstuff的内容进行排序,排序时使用内置的<运算符对只进行比较:
vector<int> coolstuff;
...
sort(coolstuff.begin(), coolstuff.end());
如果容器元素是用户定义的对象,则要使用sort(),必须定义能够处理该类型对象的operator<()函数。例如,如果为Review提供了成员或非成员函数operator<(),则可以对包含Review对象的矢量进行排序。由于Review是一个结构,因此其成员是共有的,这样的非成员函数将为:
bool operator<(const Review & r1, const Review & r2)
{
    if (r1.title < r2.title)
        return  true;
    else if (r1.title == r2.title && r1.rating < r2.rating)
        return true;
    else   
        return false;
}
有了这样函数后,就可以对包含Review对象(如books)的矢量进行排序了:
sort(books.begin(), books.end());
上述版本的operator<()函数按title成员的字幕顺序排序。如果title成员相同,则按照rating排序。然而,如果想按降序或是按rating(而不是title)排序,该如何办呢?可以使用另一种格式的sort()。它接受3个参数,前两个参数也是指定区间的迭代其,最后一个参数是指向要使用的函数的指针(函数对象),而不是用于比较的operator<()。返回值可转换为bool,false表示两个参数的顺序不正确。下面是一个例子:
bool WorseThan(cosnt Review & r1, const Review & r2)
{
    if (r1.rating < r2.rating)
        return true;
    else
        return false;
}
有了这个函数后,就可以使用下面的语句将包含Review对象的books矢量按在升序排列:
sort(books.begin(), books.end(), WorseThan);

16.3.4 基于范围的for循环(C++11)
第5章说过,基于范围的for循环是为用于STL而设计的。为复习该循环,下面是第5章的第一个示例:
double prices[5] = {4.99, 10.99, 6.87, 7.99, 8.49};
for (double x : prices)
    cout << x << std::endl;
在这种for循环中,括号内的代码声明一个类型与容器存储的内容相同的变量,然后指出了容器的名称。接下来,循环体使用指定的变量一次访问同期的每个元素。例如,对于下述摘自程序清单16.9的语句:
for_each(books.begin(), books.end(), ShowReview);
可将其替换为下述基于范围的for循环:
for(auto x : books) ShowReview(x);
根据book的类型(vector<Review>),编译器将推断出x的类型为Review,而循环将一次将books中的每个Review对象传递给ShowReview()。
不同于for_each(),基于范围的for循环可修改容器的内容,诀窍是制定一个引用参数。例如,假设有如下函数:
void InflateReview(Review &r) {r.rating++;}
可使用如下循环对books的每个元素执行该函数:
for (auto & x : books) InflateReview(x);

《C++ Primer Plus》16.3 标准模板库 学习笔记的更多相关文章

  1. 《C++ Primer Plus》第16章 string类和标准模板库 学习笔记

    C++提供了一组功能强大的库,这些库提供了很多常见编程问题的解决方案以及简化其他问题的工具string类为将字符串作为对象来处理提供了一种方便的方法.string类提供了自动内存管理动能以及众多处理字 ...

  2. C++ primer plus读书笔记——第16章 string类和标准模板库

    第16章 string类和标准模板库 1. string容易被忽略的构造函数: string(size_type n, char c)长度为n,每个字母都为c string(const string ...

  3. 标准模板库(STL)学习指南之sort排序

    对于程序员来说,数据结构是必修的一门课.从查找到排序,从链表到二叉树,几乎所有的算法和原理都需要理解,理解不了也要死记硬背下来.幸运的是这些理论都已经比较成熟,算法也基本固定下来,不需要你再去花费心思 ...

  4. 标准模板库(STL)学习指南之List链表

    本文转载自天极网,原文地址:http://www.yesky.com/255/1910755.shtml.转载请注明 什么是STL呢?STL就是Standard Template Library,标准 ...

  5. C++标准模板库Stand Template Library(STL)简介与STL string类

    参考<21天学通C++>第15和16章节,在对宏和模板学习之后,开启对C++实现的标准模板类STL进行简介,同时介绍简单的string类.虽然前面对于vector.deque.list等进 ...

  6. STL标准模板库(简介)

    标准模板库(STL,Standard Template Library)是C++标准库的重要组成部分,包含了诸多在计算机科学领域里所常见的基本数据结构和基本算法,为广大C++程序员提供了一个可扩展的应 ...

  7. 【转】C++标准库和标准模板库

    C++强大的功能来源于其丰富的类库及库函数资源.C++标准库的内容总共在50个标准头文件中定义.在C++开发中,要尽可能地利用标准库完成.这样做的直接好处包括:(1)成本:已经作为标准提供,何苦再花费 ...

  8. STL标准模板库介绍

    1. STL介绍 标准模板库STL是当今每个从事C++编程的人需要掌握的技术,所有很有必要总结下 本文将介绍STL并探讨它的三个主要概念:容器.迭代器.算法. STL的最大特点就是: 数据结构和算法的 ...

  9. 【c++】标准模板库STL入门简介与常见用法

    一.STL简介 1.什么是STL STL(Standard Template Library)标准模板库,主要由容器.迭代器.算法.函数对象.内存分配器和适配器六大部分组成.STL已是标准C++的一部 ...

随机推荐

  1. C艹函数与结构体

    传递指针 代码: #include <iostream> #include <cmath> struct polar{ double distance; double angl ...

  2. matlab中常用的函数

    find()函数: 功能:用于返回矩阵中想要的元素的索引值: 用法: index = find(X), 当X为一个矩阵时,返回的index是一个列向量,表示矩阵X中非零值的索引值,这个索引值吧,是按把 ...

  3. e612. Moving the Focus to the Next or Previous Focusable Component

    The methods to move the focus to the next or to the previous focusable component are Component.trans ...

  4. php可选缓存APC

    1.APC缓存简介 APC,全称是Alternative PHP Cache,官方翻译叫”可选PHP缓存”.它为我们提供了缓存和优化PHP的中间代码的框架. APC的缓存分两部分:系统缓存和用户数据缓 ...

  5. ubuntu -- 安装最新版的nodejs

    1.安装最新的nodejs和npm # apt-get update # apt-get install -y python-software-properties software-properti ...

  6. XAMPP permissions on Mac OS X

    $ cd /Applications $ XAMPP/ 注意: 改变的是XAMPP目录,而不是htdocs ref: http://stackoverflow.com/questions/904697 ...

  7. vimdiff的常用命令

    ★ 跳转到下一个diff点: 请使用 ]c 命令★ 跳转到前一个diff点: 请使用 [c命令如果在命令前加上数字的话,可以跳过一个或数个差异点,从而实现跳的更远.比如如果在位于第一个差异点的行输入& ...

  8. 非常酷的jQuery/HTML5图片滑块特效 带弹性菜单

    新的一周刚刚开始,当我迷迷糊糊坐在办公桌前时,又不自主的去看了一些jQuery和HTML5的应用插件,今天我们来看一款非常酷的jQuery/HTML5图片滑块特效,这款插件的特点是图片上不错的弹性菜单 ...

  9. Android 布局学习之——Layout(布局)详解二(常见布局和布局参数)

    [Android布局学习系列]   1.Android 布局学习之——Layout(布局)详解一   2.Android 布局学习之——Layout(布局)详解二(常见布局和布局参数)   3.And ...

  10. linux避免crontab的执行输出将磁盘目录占满?用户的mail占用大的空间?

    需求描述: 早上设置了ntp客户端的定时任务,发现不断的有You have new mail in /var/spool/mail/root这种提示. 然后,就看了具体的文件,由于ntpdate是每分 ...