C++STL详解

不详

Posted by liangcs71 on July 1, 2018

STL简介

部分引用自 https://www.cnblogs.com/CnZyy/p/3317999.html https://blog.csdn.net/qq_42132398/article/details/88599488

STL(Standard Template Library,标准模板库)是惠普实验室开发的一系列软件的统称。它是由Alexander Stepanov、Meng Lee和David R Musser在惠普实验室工作时所开发出来的。现在虽说它主要出现在C++中,但在被引入C++之前该技术就已经存在了很长的一段时间。

STL的代码从广义上讲分为三类:algorithm(算法)、container(容器)和iterator(迭代器),几乎所有的代码都采用了模板类和模版函数的方式,这相比于传统的由函数和类

组成的库来说提供了更好的代码重用机会。在C++标准中,STL被组织为下面的13个头文件:

<algorithm>、
<deque>、<functional>、<iterator>、<vector>、<list>、<map>、
<memory>、<numeric>、<queue>、<set>、<stack>和<utility>

一、算法

大家都能取得的一个共识是函数库对数据类型的选择对其可重用性起着至关重要的作用。举例来说,一个求方根的函数,在使用浮点数作为其参数类型的情况下的可重用性肯定比

使用整型作为它的参数类性要高。而C++通过模板的机制允许推迟对某些类型的选择,直到真正想使用模板或者说对模板进行特化的时候,STL就利用了这一点提供了相当多的有用

算法。它是在一个有效的框架中完成这些算法的——你可以将所有的类型划分为少数的几类,然后就可以在模版的参数中使用一种类型替换掉同一种类中的其他类型。

STL提供了大约100个实现算法的模版函数,比如算法for_each将为指定序列中的每一个元素调用指定的函数,stable_sort以你所指定的规则对序列进行稳定性排序等等。这样一来

,只要我们熟悉了STL之后,许多代码可以被大大的化简,只需要通过调用一两个算法模板,就可以完成所需要的功能并大大地提升效率。

算法部分主要由头文件

<algorithm><numeric><functional>

组成。

<algorithm>是所有STL头文件中最大的一个(尽管它很好理解),它是由一大堆模版函数组成的,可以认为每个函数在很大程度上都是独立的,其中常用到的功能范围涉及到比较、交换、查找、遍历操作、复制、修改、移除、反转、排序、合并等等。

<numeric>体积很小,只包括几个在序列上面进行简单数学运算的模板函数,包括加法和乘法在序列上的一些操作。

<functional>中则定义了一些模板类,用以声明函数对象。

二、迭代器

下面要说的迭代器从作用上来说是最基本的部分,可是理解起来比前两者都要费力一些(至少笔者是这样)。软件设计有一个基本原则,所有的问题都可以通过引进一个间接层来

简化,这种简化在STL中就是用迭代器来完成的。

概括来说,迭代器在STL中用来将算法和容器联系起来,起着一种黏和剂的作用。几乎STL提供的所有算法都是通过迭代器存取元素序列进行工作的,每一个容器都定义了其本身所专有的迭代器,用以存取容器中的元素。

迭代器部分主要由头文件<utility>,<iterator><memory>组成。

<utility>

是一个很小的头文件,它包括了贯穿使用在STL中的几个模板的声明,

<iterator>

中提供了迭代器使用的许多方法,而对于< memory >的描述则十分的困难,它以不同寻常的方式为容器中的元素分配存储空间,同时也为某些算法执行期间产生的临时对象提供机制,« memory >的主要部分是模板类allocator,它负责产生所有容器中的默认分配器。

这里要注意,当执行容器的erase操作的时候,删除位置后面的迭代器会失效 因此需要在erase的时候加入判断,erase的时候保存,会返回erase后面的地址


#include <iostream>
#include <vector>
using namespace std;
 
int main()
{
    vector<int> arr;
    arr.push_back(6);
    arr.push_back(7);
    arr.push_back(8);
    arr.push_back(9);

    for(vector<int>::iterator it=arr.begin(); it!=arr.end(); )
    {
        if(* it == 8)
        {
            it = arr.erase(it); //不能写成arr.erase(it);
        }
        else
        {
            ++it;
        }
    }
}

三、容器

包括各种数据结构,如vector,list,deque,set,map从实现角度来看 class template 这些都是标准库容器,下一篇文章会来讲解一下,序列式容器

序列容器包括:array(c++内建),vector,heap,pirotiy-queue,list,slist,deque,stack,queue 关联式容器: RB-tree(非公开),set,map,mutilset,multimap, 非标准:hashtable,hash_set,hash_map,hash_multiset,hash_mutilmap

四、仿函数

1、函数对象(function object)也称为仿函数(functor) 2、一个行为类似函数的对象,它可以没有参数,也可以带有若干参数。 3、任何重载了调用运算符operator()的类的对象都满足函数对象的特征 4、函数对象可以把它称之为smart function。 5、STL中也定义了一些标准的函数对象,如果以功能划分,可以分为算术运算、关系运算、逻辑运算三大类。为了调用这些标准函数对象,需要包含头文件< functional >。

总的来说就是一种重载了operator()的class或者class template,一般函数指针可以视为狭义的仿函数,比如回调函数

那么仿函数的主要作用在哪里呢

比如sort(),用户可以制定排序的策略,这个策略当作算法的参数,那么这个操作我们就需要将其设计为函数,再将函数指针当作算法的一个参数,或者将这个操作设计为一个所谓的仿函数,在语言层面是个class,在以该仿函数产生一个对象,并以此对象作为算法的一个参数

就实现观点而言,仿函数其实上就是一个行为类似函数的对象,必须自定义 operator()

比如

greater<int> ig
ig(4,6) //false  生成对象后调用 operator 调用 4,6参数
greater<int>() (6,4)   //true  先生成无名对象之后再调用 参数

五、配接器

一种修饰容器或者仿函数接口的东西,比如stack和queue,看起来是容器其实是一种容器配接器,因为他们的底层完全借助deque。改变functor接口者,称为function adapter,改变容器接口者称为container adapter,改变iterator接口者称为iterator adapter

六、配置器

负责空间配置和管理,从运用角度来说不需要考虑配置器,配置器负责底层容器空间的配置