9. STL

2019-05-22  本文已影响0人  郑行_aover

1. STL的使用方法

背景介绍
当我们在做项目的时候,如果用到list或者map这种数据【】结构的时候,由于没有现成的代码,所以常常需要自己先实现这个功能。
整个软件领域里,数十年来确实都在为了一个目标而奋斗--可复用性(reusability),这看起来似乎并不夸张。从最早的面向过程的函数库,到面向对象的程序设计思想,到各种组件技术(如:COM、EJB),到设计模式(designpattern)等等。而STL也在做着类似的事情,同时在它背后蕴涵着一种新的程序设计思想--泛型化设计(generic programming)。

说明
STL(StandardTemplate Library),即标准模板库,是一个具有工业强度的,高效的C++程序库。
STL 提供六大组件,彼此可以组合套用:

1.容器(containers):

各种数据结构,如 vector, list, deque, set, map用来存放数据。,STL 容器是种 class template

  1. 算法:

各种常用算法如 sort, search, copy, erase…,从实作的角度看,STL 算法是种 function template。

3.迭代器(iterators):

扮演容器与算法之间的胶着剂,是所谓的「泛型指标」,有五种类型,以及其它衍生变化。从实作的角度看,迭代器是一种将 operator*, operator->, operator++, operator-- 等指标相关操作予以多载化的class template。所有 STL 容器都附带有自己专属的迭代器 — 是的,只有容器设计者才知道如何巡访自己的元素。原生指标(nativepointer)也是一种迭代器。

4.仿函数(functors):

行为类似函式,可做为算法的某种策略(policy),仿函式是一种重载了 operator()的 class 或class template。一般函式指标可视为狭义的仿函式。

  1. 配接器(adapters):

用来修饰容器(containers)或仿函式(functors)或迭代器(iterators)接口的东西。例如 STL 提供的 queue 和stack,虽然看似容器,其实只能算是一种容器配接器,因为它们的底部完全借重 deque,所有动作都由底层的 deque 供应。改变 functor 接口者,称为 function adapter,改变 container 接口者,称为 container adapter,改变iterator 界面者,称为 iterator adapter。配接器的实作技术很难一言以蔽之,必须逐一分析。

6.配置器(allocators):
负责空间配置与管理,配置器是一个实现了动态空间配置、空间管理、空间释放的 class template。

http://www.cplusplus.com/reference/stl/更加详细的资料



常见的错误问题:

将一个容器初始化为另一个的副本
将一个容器复制给另外一容器的时候,类型必须匹配,容器类型和元素类型必须相同,为什么呢?

int main () {
       std::vector<char> vec1(10,1);
       std::vector<float> vec2(vec1);
       return 0;
}

我认为用一个容器去初始化另一个容器的时候调用的是构造函数,既然是拷贝构造函数,那么传的参数容器和该容器本身应该是同一个容器类型.

初始化为一段元素的副本
尽管不能直接将一种容器内的元素复制给另外一种容器,但是系统还是允许通过传递一个迭代器来初始化,不过这里的迭代器不需要他们的容器类型相同,容器内的元素类型也可以不相同,只要能相互兼容。

比如

Test3.cpp
#include <iostream>     // std::cout
#include <algorithm>    //std::replace
#include <vector>       // std::vector
#include <list>
using namespace std;
int main () {
         vector<int>vec1(10,1);
         list<int>vec2(vec1.begin(),vec1.end());
   return 0;
}
Test3.cpp
#include <iostream>     // std::cout
#include <algorithm>    // std::replace
#include <vector>       // std::vector
#include <list>
using namespace std;
int main () {
   vector<char> vec1(10,1);
   vector<double> vec2(vec1.begin(),vec1.end());
   return 0;
}

g++ -o test Test3.cpp

为什么呢?先别着急,后面的环节将会说道迭代器的细节。我们之暂时保留对他的用法认识

int main () {
         floata=12;
         vector<float&>vec1(10,a);
   return 0;
}

这段代码有什么问题吗?(相信聪明的你已经发现了他的问题:因为这个容器里的每个元素类型都是引用类型的,但是我们又知道引用类型的不支持赋值预算,所以他是不合法的代码)

迭代器之间的关系操作符比如>,<,>=,<=适用于vector和deque,想想为什么?因为他们的内存布局,他们的内存块都是连续分配的,所以可以直接想数组一样的操作对地址进行比较,但是像list,map就不一样的,你无法确定按顺序存放的元素的地址也是不是按顺序分配的内存呢。

因此底下的代码看看有什么问题呢:

list<int> l;
list<int>::iterator  it1=l.begin(), it2=l.end();
while(it1<it2){
   //…..
}

我们所认识的list其实它就相当于链表,其内存并不是我们想象的那样连续分配的,所以对it1和it2的大小,我们不可而知,这将会产生什么后果,你懂得。

上一篇下一篇

猜你喜欢

热点阅读