STL(四)泛化技术基础

    STL(Standard Template LIbrary)标准模板库提供了大量的模板类和模板函数,大大简化了数据结构和算法的代码编写任务。

   考虑到在编译和应用上的一些因素,如模板类型的安全性检查、编译速度和减少语言的依赖性等,C++STL在广泛使用模板编程的同时,还引入了诸多concept概念、迭代器和函数对象等技术性的内容。

一、C++ STL的发展历程

     1971年左右引进泛型设计

     1984年Alexandar Sepanov与Musser合作,分别在Scheme语言和Ada语言上开发出泛型的数据结构和算法函数库。

     1987年,Alexandar Sepanov转而为C/C++语言开发泛型库,当时C++还未提供模板的编程技术。一同在AT&T实验室工作的C++创始人Bjarne Stroustrup,从Ada语言中借鉴泛型编程,为C++语言引入了模板的编程,以简化C/C++泛型库的开发。

     1988年 Alexandar Sepanov 进入HP工作

     1992年 Alexandar Sepanov重新返回到C++STL泛型库的研究,最终与Meng Lee合作实现了HP版本的C++ STL

     1993年Alexandar Sepanov向ANSI/ISO C++标准委员会建议,将STL通用库纳入C++标准

     1998年 ,STL成为标准化

      为了确切把握STL泛型库所蕴含的设计思想,这里介绍一下STL之父Alexandar Sepanov的一些背景

      Alexandar Sepanov,1950年出生于前苏联的莫斯科。曾在莫斯科大学研究数学。他在研究泛型库时,首先是从算法着手,找到具体算法步骤之后,就分析算法每一步骤所需要的条件,然后再归并出整个算法所需要满足的最一般性条件,即最弱的条件。所找出的这些算法条件,其实就是C++ STL所谓的concept概念

     如果将泛型库的泛化工作与20世纪中叶由法国布尔巴基学派所倡议的结构数学的研究作一比较,会发现两者殊途同归,都是从具体的证明步骤或算法步骤中,提炼出公理性条件,然后再从这个公理性条件出发,参考具体情形下的证明或算法步骤,给出一般性的证明步骤或算法步骤。STL的迭代器Iterator是C/C++指针的一般化推广。

二、STL的体系结构

     STL泛型库由容器、迭代器、算法、函数对象、适配器、内存分配器、概念以及模型等几大部分组成,其中最关键的组件是容器和算法,其他则是围绕它们进行开发或使用的附带产物。

      1、容器(Container)

       泛型数据结构用模板类给出,统称为容器类,包括vector, list, queue, set, 等,每个容器类都可以传入一个具体的类型,具现出一个非模板的类。

      2、迭代器(Iterator)

       传统上读写数据结构中的数据,一般都是通过移动读写指针来进行的。在STL中,对容器的数据读写,通过迭代器来进行。迭代器是指针的一个泛化,在容器和算法之间充当桥梁的作用,是STL泛型库最核心的一个组成部分。

      具体地说,各种C++ STL容器都需要定义一个迭代器,以指示容器的当前数据读写位置,有两种比较常用的方法

      一是简单地定义,在容器类X中定义一个迭代器iterator,如下:

template<class T>
class X {
public:
       typedef  T*    iterator;   //定义迭代器iterator
       ...
};
      另一种则是采用一个类或结构体定义出来,如链表节点指针泛化的迭代器,需要在迭代器中重载“++”或“--”操作符。

     3、算法(Algorithm)

     把常用的排序、交换、查找和搜索等算法以泛化算法实现到C++ STL库中,避免不必要的重复设计。

     如果将算法作为各个容器的成员函数,放在容器中进行实现,算法将依赖于具体的数据结构,明显会有失应用的一般性。

     *把数据结构中用来读写数据的指针,泛化为迭代器,然后,将算法架构在迭代器之上,把迭代器值作为它的参数,就可脱离具体的容器而实现出通用的算法函数 ,如下面find算法函数表示,参数first和last是迭代器,指示查找的起始和结束位置,val参数是所要查找的某个类型值。

template <class InputIter, class T>
inline InputIter find(InputIter first, InputIter last, const T& val, input_iterator_tag)
{
       while (first != last && !(*first == val)) 
            ++first;
       return  first;
}
      *把算法应用到容器,只需将相关的迭代器值传入算法即可。下面是一个用find算法在vector上查找某值元素的例子,返回所找到元素的迭代器值。

#include <vector>
#include <iostream>
#include <algorithm>
int main(void)
{
    using namespace std;
    vector<int>     v;
    v.push_back(6);
    v.push_back(8);
    v.push_back(31);
    //
    vector<int>::iterator  result = find(v.begin(), v.end(), 8);
    cout << *result << endl;
    return 0; 
}
     4、函数对象(Function Object)

       函数的传递当然可用泛化的函数指针来进行,但是STL常使用的是函数对象,目的在于用更简洁、不依赖于当前计算机硬件体系的方式来表达算法。

template <class InputIter, class Function>
Function for_each(InputIter first, InputIter last, Function f) {
    for (; first != last; ++first) 
        f(*first);    //调用函数
    return f;   //返回函数对象
}
      STL中,定义了若干函数对象,包括算术运算plus, minus, 等

    5、适配器(Adapter)

    STL中所渭的适配器,作用相当于一个类型转换。

    6、内存分配器(Allocator)

    STL的内存分配器是一些用于内存管理的模板类,可支持高层次和高性能的内存管理。内存分配器通过malloc和realloc函数进行底层的内存分配,一次分配大块的内存后,动态生成的对象内存分配,可在大块内存中依最小碎片原则进行划分和重整。内存分配器为若干对象的内存分配和释放提供了高级形式的调用,方便各种容器对元素数据进行内存管理。

    7、概念(Concept)和模型(Model)

    在代码的开发阶段及时发现错误,一个较为有效的方法是,为泛型库算法函数的所有模板类型,从算法的实现步骤中归纳出相应的一个概念,用概念来指出用于具现的类型必须满足的运算条件,而满足某个概念所定义条件的类型,则称为该概念的一个模型。

    例如,InputIterator概念指出了迭代器必须具有!=, ==, *和++运算,Int* 和 double* 指针都是InputIterator概念的一个模型。

五、STL存在的一些问题

   





       

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值