09STL讲解Word格式.docx
《09STL讲解Word格式.docx》由会员分享,可在线阅读,更多相关《09STL讲解Word格式.docx(16页珍藏版)》请在冰豆网上搜索。
【对象】
编译期运行期
2.类模板的静态成员变量,每个实例类各有一份。
3.类模板的模板参数可以带有缺省值(从右边缺省开始)。
PS:
函数模板的参数不能带有缺省值。
四.模板的特化
1.对于某些特定类型而言,通用模板可能并不适用,可以为通用模板提供一种特殊化的定义,作为一般情况之外的特例,为编译器提供一种更为合适的选择。
2.对于类模板,既可以将整个类模板全部特化,也可以只针对具体类型相关的个别成员函数进行特化。
(注意:
使用成员特化时,特化版本和通用版本的规格必须完全一致。
)
当使用模板类型做多文件编程时,需要main.cpp文件包含classTemplate.h文件
classTemplate.h文件包含classTemplate.cpp文件
五.编译模型
1.后期编译
(1)模板定义只是一种规范描述,而非真正的类型定义。
当编译器看到模板定义时,仅做一般性的语法检查,同时保存一份模板的内部表示,并不生成二进制指令。
(2)当编译器看到模板被实例化为具体函数或类,才真正用模板的内部表示结合类型实参,生成指令代码。
(3)每个C++语言的源文件是单独编译的。
因此编译器仅在编译包含模板定义的源文件时保存内部表示。
(4)如果模板的实例化与他的定义不再同一个编译单元中,模板就失去被编译的机会,进而导致链接错误。
2.包含模型
1)将模板的声明和定义放在一个头文件中,或者在其头文件中通过#include预编译指令包含定义该模板的源文件。
2)包含模型的缺陷
A)暴露了用户不希望或者不了解的实现细节;
B)模板头文件被多个源文件包含,会延长编译时间。
3.分离模型
在定义模板的源文件中,加入一个export声明:
Comparatro.cpp
当编译器看到某个模板被声明为导出(export)型,会将该模板的内部表示缓存到一个临时文件中。
编译器编译到对该模板的实例化代码时,在从这个临时文件中重新读取其内部表示,完成编译和链接。
注意:
绝大多数C++编译器都不支持分离模型,而且在新C++11标准中已经删除了分离模型,并将export关键字移做它用。
六.类模板的局部特化
1.针对部分类型参数取特定类型进行特化;
编译器优先选择特化程度最高的版本。
3.针对类型参数之间的某种关联性进行特化;
编译器优先选择匹配程度最高的版本。
4.针对指针或者数组进行特化;
编译器优先选择针对指针或数组的特化版本。
范例:
partial.cpp
注意:
当编译器发现同时存在多个匹配程度一样的版本时,会报告歧义错误。
七.非类型参数
1.模板既可以带有类型参数,也可以带有非类型参数,传递给非类型参数的实参只能是常量/常量表达式/常属性(const)的变量,且不能同时具备挥发性(volatile)。
2.类模板的非类型参数和类型参数一样,也可以带有缺省值。
模板的非类型参数不能是浮点数,也不能是类类型。
模板的非类型实参不能是字符串字面值。
模板的非类型实参不能是全局指针,模板的非类型实参可以是外部变量。
八.模板的嵌套和递归
List<
Array<
int>
>
la
Array<
List<
al
aa
九.模板型模板实参
十.类模板中的模板函数
十一.class和typename
Class——-类
\模板
/参数
typename——解决嵌套依赖
Day02
模板应用(容器、迭代器、泛型算法)STL
容器:
借助于模板语法实现抽象化的数据结构。
迭代器:
提供一种与具体的数据结构无关的、统一的、针对容器元素的访问方法。
泛型算法:
借助模板语法实现抽象化的数据处理。
一.容器
以双向线性链表模板为例。
二.迭代器:
在不暴露容器内部表示的前提下,使用户以一种一致且透明的方式访问容器中的对象。
1.迭代:
从一个到下一个。
2.类类型的对象,来模拟一个数组指针遍历的行为。
3.封装实际指针,提供指针所支持的运算符:
==,!
=,++,--,*,->
,
三.泛型算法:
借助于迭代器,以泛型的方式处理容器中的对象。
Boost
Day03
一.STL
1.STL的特性
1)STL里的所有组件,都是通过模板定义的,全面支持泛型
2)STL所追求的目标是最大程度上降低数据结构和算法与具体数据类型的相关性。
3)STL的设计宗旨就是通过一个尽量小的框架,实现尽量大的弹性。
2.STL的主要容器类型
下面三种线性容器:
强调元素之间的前后关系
1)向量(vector):
内存连续,可以进行下标访问。
(可代替数组)
2)列/链表(list):
内存不连续,不能以下标访问,随机的插入/删除高效。
3)双端队列(deque):
类似于相量,但两端都是开放的。
下面三种容器:
合称为适配器容器,构建于三种线性容器之上的封装。
4)堆栈(stack):
在一端的压入和弹出,后进先出。
5)对列(queue):
从一段压入,从另一端弹出,先进先出。
6)优先队列(priority_queue):
从一段压入,从另一端弹出,优者先出。
下面四种容器:
合称为关联容器。
7)映射(map):
通过平衡有序二叉树,存放key-value对的集合,提高搜索性能。
key必须唯一,一一对应关系。
8)多重映射(multimap):
允许key重复的映射。
一对多的关系。
9)集合(set):
没有value的映射。
10)多重集合(multiset):
没有value的多重映射。
平衡二叉树:
对任何一个节点,它的左子树的深度与右子树的深度最大相差1。
3.STL容器的共性
1)所有的容器都支持深拷贝
2)所有的容器都可以和同型容器做关系比较(>
<
==!
=…..)
3)容器中的元素都是副本
4)所有的容器都支持迭代器(支持泛型算法)
二.向量(vector)
1.基本特性
1)存储结构:
使用一段连续的内存空间来存放数据。
2)具备常数时间的随机访问特性(下标访问)。
3)支持下标运算符。
4)支持动态内存管理:
(向量将他所有的元素存放在一个连续的内存块中,这并不
会妨碍新元素被无限地插入到容器中。
如果当前内存无法满足一个向量中所有元素连续存放的需要,那么这个向量就会自动转移到一个新的内存位置,原先位置上的所有元素都将被复制到新分配的内存中,而原先的内存空间被释放)。
5)通过预分配空间来降低动态内存管理的开销。
6)也支持随机位置的插入/删除,但是只有在尾部做插入/删除才是高效的。
2.实例化
#include<
vector>
1)vector<
元素类型>
向量对象;
如:
vector<
vi;
2)vector<
向量对象(初始大小);
vi(10);
初始预分配空间范围内的元素,基本类型:
初始化为0;
类类型:
调用缺省构造函数初始化。
3)vector<
向量对象(初始大小,初值);
vi(10,1234);
用初值值初始化预分配空间内的每个元素。
4)vector<
向量对象(起始迭代器,终止迭代器);
用另一个容器从起始迭代器,到终止迭代器之前为止的范围内的元素,来初始化所构造的向量。
intarr[5]={1,2,3,4,5}
Vector<
vi(arr,arr+5);
Vector<
vi(&
arr[0],&
arr[5]);
3.函数front/back/push_back/pop_back,注意不能再首端push/pop操作
4.迭代器
1)四个迭代器
iterator/const_iterator
reverse_iterator/const_reverse_iterator
2)随机迭代器
A只有连续内存的容器(vector/deque)才有随机迭代器。
B支持和整数的加减运算,支持迭代器的比较和相减运算。
3)迭代器的分类
按照迭代方向分:
正向/反向迭代器
按照访问特性分:
可写/只读迭代器
按照迭代特性分:
顺序/随机迭代器
vector:
:
iterator正向、可写、随机
list:
const_reverse_iterator反向、只读、顺序
5.insert/erase函数
6.大小和容量
大小:
实际容纳元素的个数
容量:
最多容纳元素的个数(vector的容量只增不减)
size()——返回大小
resize()——改变大小,可增可减,增则构造,减则析构。
max_size()——返回向量的最大容量(也可insert/push_back元素)
Clear()——等价于resize(0)清空
empty()——判断是否为空
capacity()——返回容量
reserve()——预留容量,只增不减,新增部分不初始化
向量的容量无论是通过resize(),还是通过调用reserve(),都是只增不减的。
因此向量不适宜保存大对象,如果对象需要使用较多的资源,建议通过构造和析构函数来动态分配和释放该资源。
vector<
Student*>
vs;
vs.push_back(newStudent());
7.查找和排序
#include<
algorithm>
find():
原型iteratorfind(iteratorbegin,iteratorend,constvalue_type&
val)
在begin和end之间查找与val相匹配的第一个元素,返回该元素的迭代器,如果查找失败,返回第二个参数end。
sort():
原型voidsort(iteratorbegin,iteratorend);
voidsort(iteratorbegin,iteratorend,lesscmp);
比较器:
就是一个返回bool类型值,用于判断第一个元素参数是否小于第二个元素参数的函数或函数对象。
bool比较器函数(元素类型const&
a,元素类型const&
b){
if(a<
b)
returntrue;
else
returnfalse;
}
Class比较器类{
public:
booloperator()(元素类型const&
b)const{
if(a<
Sort()函数的三参数版本的第三个参数,是比较器函数指针,或比较器对象。
PS:
类对象的查找,需要重写==操作符,类对象的排序,需要重写<
操作符
8.类类型的向量
元素类型往往需要考虑以下问题:
1)是否支持深拷贝(拷贝构造、拷贝赋值)
2)是否支持相等性==比较,find()函数重载“==”或类型转换
3)是否支持<
运算符,sort()函数重载“<
”或比较器
size_typestring:
:
find_first_of(stringconst&
str,size_typepos=0);
返回调用字符串中,从pos处开始的,第一个出现在str字符串中的字符的下标。
如果没有出现在str字符串中的自字符,则返回string:
npos。
三.字符串(string)
1.源自basic_string<
T>
模板的类型别名
typedefbasic_string<
char>
string;
wchar_t>
wstring;
char是一个字节,string表示多字节字符串。
ACSLL/GBK/UFT-8
wchar_t两/四个字节,wstring表示宽字符字符串。
UCS-2/UCS-4
2.创建字符串
stringstr;
stringstr(“zzg”);
stringstr=“zzg”;
string*str=newstring;
string*str=newstring();
string*str=newstring(“zzg”);
c风格的字符串===》C++风格字符串(直接复制/构造)
chararr[]=“Helloword!
”
stringcpps=arr;
stringcpps(arr)
c++风格的字符串===》c风格字符串
stringcpps=“zhaozhigao”;
char*arr=cpps.c_str();
3.字符串的运算
1)拼接+
2)赋值=/+=
3)关系<
/<
=/>
/>
=/!
=/==,大小写敏感
4)输入/出>
>
<
(VC6不支持)
5)下标运算[](当数组使用)
4.大小和容量
size/resize/clear/empty/capacity/reserve(与向量vector的特性一样)
stringstr(“123456789”);
str.length()====》9
str.size()=======》9
strlen(str.c_str())====》9
sizeof(str)=======》4(32位)/8(64位)指针
5.拼接、搜索、子串
string&
append(conststring&
str);
相当于“+=”
stirng&
str,size_typepos,size_typelen);
将str中从第pos个字符开始,截取len个字符拼接到调用字符中,并返回调用字符串。
append(size_typenum,charch);
在调用字符串的末尾拼接num个ch字符。
size_typefind_first_of(stringconst&
在调用字符串中,从pos处开始的,第一个出现在str字符串中的字符的下标。
如果没有出现在str字符串中的字符,则返回string:
size_typefind_first_not_of(stringconst&
在调用字符串中,从pos处开始的,第一个没有出现在str字符串中的字符的下标。
如果没有这样的字符,则返回string:
size_typefind_last_of(stringconst&
str,size_typepos=string:
npos);
在调用字符串中,从pos处开始的,最后一个出现在str字符串中的字符的下标。
size_typefind_last_not_of(stringconst&
在调用字符串中,从pos处开始的,最后一个没有出现在str字符串中的字符的下标。
Stringsubstr(size_typepos,size_typelen=string:
返回调用字符串中从pos处开始,len个字符的子串。
String:
string(conststring&
str,size_typepos,size_typelen=string:
构造函数,构造字符串,用字符串str中从pos处开始,len个字符的子串。
6.字符串的单字符访问
1)下标运算符:
str[i],不检查下标越界
2)char&
at(size_typeindex);
,会检查下标越界,抛出std:
out_of_range异常
charconst&
at(size_typeindex)const;
7.字符串的查找和替换
size_typefind(conststring&
str,size_typepos);
返回调用字符串中从pos处开始第一次出现str的首字符下标。
若没有找到,则返回string:
npos
string&
replace(size_typepos,size_typelen,stringconst&
str);
将调用字符串从第pos个字符开始的len个字符串替换为str字符串,同时返回调用字符串的自引用。
8.插入和删除
insert(size_typepos,conststring&
在调用字符串第pos个字符前面插入str字符串。
erase(size_typepos=0,size_typelen=string:
从调用字符串第pos个字符开始删除len个字符。
9.交换和复制
voidswap(string&
from);
将调用字符串和from字符串的内容做交换。
assign(stringconst&
将字符串str复制到调用字符串,相当于string中的‘=’
将字符串str的第pos个字符开始,复制len个字符到调用字符串
10.begin/end/rbegin/rend等于向量的使用
push_back/c_str/data/copy
Day04
一.双端队列(deque)
1.除了capacity()和reserve()以外,向量的接口双端队列都有。
2.双端队列增加了在头部压人和弹出的接口。
Push_front/pop_front
3.虽然双端队列的物理结构也是连续的内存,但是它在其内存空间的首尾两端都保持了适度的开放性。
因此在距离首尾两端等距的位置做insert/erase,性能是一致的。
4.和向量一样也支持下标访问元素和随机迭代器访问容器中的元素。
5.所占用的内存空间比向量要略多一些。
动态内存管理所花费的时间也比向量要略多一些。
对容器所做的结构性的改变(push_back/push_front/pop_back/pop_front/erase
/insert/resize/clear),会导致原先初始化的迭代器不再指向先前的元素,如果需要保证迭代器和其目标的相对位置不变,需要人为的同步迭代器。
二.链表(list)
1.链表是按照链式线性表的形式存储数据。
每个数据元素存放在内存不连续的节点中。
2.不支持下标运算,也不支持随机迭代器。
3.大部分成员函数和双端队列一样。
front/push_front/pop_front/back/push_back/pop_backinsert/erase——o
(1)
size/resize/clear/emptybegin/end/rbegin/rend
PS:
当链表中的数据发生改变(erase)时,要重新获得迭代器。
4.特有的成员函数
remove—删除所有匹配的元素
unique—连续重复的元素做唯一化
splice—将参数列表的全部或一部分插入到调用列表中
voidsplice(iteratorpos,list&
lst);
将lst全部(剪切)插入到调用列表的pos之前
voidsplice(iteratorpos,list&
lst,iteratordel);
将lst中del所指向的元素(剪切)插入到调用列表的pos之前。
voidsplice(iteratorpos,list&
lst,iteratorstart,iteratorend);
将lst中从start开始到end之前的元素(剪切)插入到调
用列表的pos之前。
merge—将有序的参数列表合并到有序的调用列表中,并保证合
并以后的结构依然有序。
voidmerge(list&
lst);
voidmerge(list*lst,lesscmp);
第二个参数:
比