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
- 算法:
各种常用算法如 sort, search, copy, erase…,从实作的角度看,STL 算法是种 function template。
3.迭代器(iterators):
扮演容器与算法之间的胶着剂,是所谓的「泛型指标」,有五种类型,以及其它衍生变化。从实作的角度看,迭代器是一种将 operator*, operator->, operator++, operator-- 等指标相关操作予以多载化的class template。所有 STL 容器都附带有自己专属的迭代器 — 是的,只有容器设计者才知道如何巡访自己的元素。原生指标(nativepointer)也是一种迭代器。
4.仿函数(functors):
行为类似函式,可做为算法的某种策略(policy),仿函式是一种重载了 operator()的 class 或class template。一般函式指标可视为狭义的仿函式。
- 配接器(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
为什么呢?先别着急,后面的环节将会说道迭代器的细节。我们之暂时保留对他的用法认识
-
容器内元素类型约束
大多数类型都可以作为容器的元素类型。元素类型必须满足一下2个约束:- 元素类型必须支持赋值运算(因为要牵扯到容器内元素的计算修改)
- 元素类型的对象必须可以复制
此外关联容器还有其他约束。
因为引用和IO库类型的不支持赋值运算
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的大小,我们不可而知,这将会产生什么后果,你懂得。
网友评论