stl基础知识,stl基础及应用
来自:http://blog . . net/byxdaz/article/details/4633826 #评论
STL是标准模板库,标准模板库。这可能是历史上最令人兴奋的工具之一的最无聊的术语。从根本上说,STL是一个“容器”的集合,比如链表、向量、集合、映射等。STL也是算法和其他组件的集合。这里的“容器”和算法的集合,指的是世界上很多聪明人多年来的杰作。它是c++标准库的重要组成部分,最初是由斯捷潘诺夫和李等人开发的。而且几乎是和C++同时开发的。一开始STL选择Ada作为实现语言,但是Ada有点让人失望。最后他们选择了已经有模板的C++。STL又被添加到c++库中了。1996年,惠普公司免费发布了STL,为STL的推广做出了巨大贡献。STL提供了类型安全、高效、易用的特性,无疑是C程序员最引以为傲的部分。每个c++程序员都应该好好学习STL。一般包括容器、算法和迭代器,容器和算法可以通过迭代器无缝连接。
一、基础知识
1.通用技术
实现泛型技术的方法有很多,比如模板、多态等。模板是在编译时确定的,多态是在运行时确定的,其他的如RTTI也是在运行时确定的。多态性是通过在运行时查找虚拟表来实现的。例如,如果一个类有一个虚方法,那么这个类的实例的内存起始地址就是虚表地址。可以将内存起始地址强制成int*获取虚拟表,然后(int*)*(int*)获取虚拟表中第一个函数的内存地址,再强制成函数类型,可以调用这个函数来验证虚拟表机制。
泛型编程(以下简称GP)是一种全新的编程思想。与众所周知的OO、OB、PO等编程思想不同,GP具有更高的抽象性,基于GP设计的组件耦合度更低,没有继承关系,因此其互操作性和可扩展性非常高。众所周知,任何算法都是在特定的数据结构上工作的。最简单的例子就是快速排序最根本的实现条件是排序后的对象存储在一个数组中,因为快速排序是因为数组的随机存储特性,即单位时间内可以交换距离较远的对象,而不仅仅是相邻的两个对象。但是如果用关联表存储对象,因为在关联表中获取对象的时间是线性的,也就是O[n],所以会进行快速排序。也就是说,我们在设计算法的时候,总是要先考虑它所应用的数据结构,比如数组查找、关联表查找、树查找、图查找等。算法的核心是搜索,但由于数据结构的不同,会有很多不同的表现形式。数据结构和算法之间如此紧密的关系,一直是我们之前的认识。泛型设计的基本思想是将算法与其数据结构分离,也就是说,我们在设计算法的时候,并不考虑我们设计的算法会用在什么数据结构上。通用设计的理想状态是搜索算法可以作用于各种数据结构,如数组、关联表、树、图等。成为一个通用的、通用的算法。
2.四种类型的转换运算符
Static_cast以逻辑方式转换一个值。当应用于类的指针时,意味着它允许子类类型的指针转换为父类型的指针(这是一种有效的隐式转换),同时,它还可以执行相反的动作:将父类转换为其子类。
例子:float x;
将static_cast int //Output X计为整数值
Dynamic_cast将多态类型向下转换为实际的静态类型。仅用于指向对象的指针和引用。当用于多态类型时,它允许任意隐式类型转换和相反的过程。Dynamic_cast将检查操作是否有效。也就是说,它将检查转换是否会返回所请求的有效且完整的对象。检测在运行时执行。如果转换后的指针不是所请求的有效且完整的对象指针,则返回值为NULL。
例子:类车;
Cabriolet级:公共汽车{
…
};
Limousline级:公共汽车{
…
};
无效f(汽车*cp)
{
敞篷车*p=dynamic_cast敞篷车
}
将一个指针转换成另一种类型的指针。它还允许从指针到整数类型的转换。反之亦然,达拉斯到礼堂这种运算符可以在不相关的类型之间转换。结果只是从一个指针到另一个指针的值的二进制副本。任何类型都不会检查和转换类型之间指向的内容。
例如:
A类{ };
B类{ };
A * a=新A;
B * b=reinterpret_cast B *
Const_cast一般用于强制消除对象的恒常性。
例如:
C类{ };
const C * a=new C
C *b=const_cast C *
其他三个运算符不能修改对象的恒定性。
3.由explicit修改的构造函数不能用作转换函数。很多情况下,隐式转换是有意的,也是正当的。但是有时候我们并不想要这种自动转换。
例如,为了避免这种隐式转换,具有单个参数的构造函数应显式声明如下:
类别字符串{
int大小;
char * p;
//.
公共:
//不要隐式转换
显式字符串(int SZ);
String (const char *s,int size n=0);//隐式转换
};
void f()
{
字符串s(10);
s=100//现在编译时出现错误;需要显式转换:
s=字符串(100);//OK;显式转换
s= st//OK;此时允许隐式转换。
}
4.命名空间命名空间
解决使用不同模块和库时的名称冲突问题。
5.C标准库中的常用工具。它由类和函数组成。这些工具包括:
几种常见类型
一些重要的C函数
数值极值
二。STL的六个组成部分
容器(集装箱)
算法(算法)
迭代器
模仿功能对象
适配器(转接器)
空间分配器
1.容器
作为STL-container最重要的组成部分,它可以分为向量、队列、列表、队列、堆栈、集合、多重集合、映射和多重映射。
任何元素都可以在恒定的时间内被访问和修改,序列末尾的插入和删除具有恒定的时间复杂度。任何一项的插入和删除的时间复杂度都与到终点的距离成正比,尤其是向量头的添加和删除成本高得惊人。
矢量
对任何元素的访问都与到两端的距离成正比,但在某个位置插入和删除一个项目需要恒定的时间。
目录
是堆栈项目的有限序列,并且满足序列中删除、检索和修改的项目只能是最近插入到序列中的项目。按照后进先出的原则。
堆
由节点组成的红黑树,每个节点包含一个元素,节点由作用于该对元素的一些谓词来排列。没有两个不同的元素可以有相同的顺序,所以它有快速搜索的功能。但是,这是以牺牲插入和删除操作的效率为代价的。
设置
2.算法
该算法主要由头文件算法、数值算法和函数算法组成。算法是所有STL头文件中最大的。它是由大量的模板函数组成的,可以认为每个函数在很大程度上是独立的。其中,常用的功能范围涉及比较、交换、搜索、遍历、复制、修改、删除、反转、排序、合并等。Numeric很小,只包括几个对序列进行简单数学运算的模板函数,包括对序列的一些加法和乘法的运算。Functional定义了一些模板类来声明函数对象。
STL的算法也很优秀。大部分都是通用的,基本都是用c++模板实现的。这样很多类似的函数就不用自己写了,用函数模板就可以了。
我们在使用算法的时候要针对不同的容器,比如在搜索集合的时候最好不要使用通用函数find()。当它用于集合时,它的性能很差。最好使用集合自带的find()函数,该函数针对集合进行了优化,性能非常高。
3.迭代程序
它的具体实现在迭代器中,不管迭代器类是如何实现的,我们都可以完全理解为指针。很多时候,把它理解成指针是没有问题的(指针是迭代器的特例,也属于迭代器)。但是,一定不能做到彻底。
4.模仿功能
模仿函数,或称函数对象,是STL的六个组成部分之一。虽然模仿函数很小,但是极大的扩展了算法的功能。几乎所有算法都有模仿函数版本。例如,搜索算法find_if是find算法的扩展。标准搜索是在两个元素相等时找到的,但是什么是相等在不同的情况下需要不同的定义,比如地址相等、地址和邮政编码相等。虽然这些等式的定义在变,但算法本身并不需要改变,这要归功于模仿功能。函子,也称为函数对象,实际上是重载()运算符的结构。没什么特别的。
例如,下面的代码定义了一个二元判断函子:
无结构整型
{
布尔运算符()(int left,int right)常量
{
返回(左向右);
};
};
为什么要用模仿功能?
1).模仿函数比一般函数更灵活。
2).仿函数有类型识别,可以作为模板参数。
3).模仿函数的执行速度比函数和指针快。
如何使用模仿功能?
除了在STL里,你在别的地方很少会看到模仿函数。在STL中,模仿函数最常用作函数或模板的参数。
STL有自己预定义的模仿函数,比如all运算符,比如=,-,*,‘’的模仿函数比较少。
模板类_Ty
无结构:public binary_function _Ty,_Ty,bool
{ //运算符的函子
布尔运算符()(常数_类型_左,常数_类型_右)常数
{ //将运算符应用于操作数
return(_ Left _ Right);
}
};
从上面的定义可以看出,从binary_function继承的少.那么什么是二元函数呢?
模板class _Arg1,class _Arg2,class _Result
结构二元函数
{ //二进制函数的基类
typedef _ arg 1 first _ argument _ type;
typedef _ arg 2 sec _ argument _ type;
typedef _ Result result _ type
};
其实binary_function只是做一些类型声明,别的什么都不做,但是为什么要用STL做这些事情呢?如果你看过STL的源代码,你会发现有很多这样的用法,但是它们没有别的目的,只是为了方便,安全,复用等。但是,由于STL是默认的,所以作为程序员必须遵循这个规则,否则你将无法安全地使用STL。
比如我们自己设置一个模仿函数。这边走:
模板类型名称类型1,类型名称类型2
class func _ equal:public binary _ function type 1,type2,bool
{
Inline bool operator () (type1t1,type 2t 2)const//这里不能少const。
{
返回t1==t2//当然这里需要重载==了
}
}
我们来看这行:inline bool operator () (type1t1,type 2t 2)const//这里不能少const。
Inline被声明为内联函数。我觉得这里没必要说什么了。关键是为什么声明为const?如果想找出原因或者看一下源代码,补充一下如果我们在这里写一行代码,find _ if (s.begin(),s.end(),bind2nd (func _ equal(),temp)),bind2nd函数中的参数是const type,const type对象,只能访问cosnt修饰函数!
与二元函数相反,一元函数的用法与二元函数相同。
结构一元函数{
typedef _A参数类型;
typedef _ R result _ type
};
注意:仿函数是重载()的类,重载的函数应该是const。如果要自定义模仿函数并在STL适配器中使用,必须从binary_function或unary_function继承。
5.适配器
适配器是STL组件,用来修改其他组件的接口,是带一个参数的类模板(这个参数是操作的值的数据类型)。STL定义了三种类型的适配器:容器适配器、迭代器适配器和函数适配器。
容器适配器:包括栈、队列和priority_queue。使用容器适配器,堆栈可以实现为基本容器类型(向量、出列、列表)的适配。栈可以看作是一个特殊的vctor、deque或者list容器,但是它的操作仍然受到栈本身属性的限制。和queuepriority _ queue类似。适配器的接口更简单,但比一般容器更受限制。
迭代器适配器:一个STL组件,修改为一些基本容器定义的迭代器的接口。反向迭代器和插入迭代器都属于迭代器适配器,扩展了迭代器的功能。
函数适配器:可以通过转换或修改其他函数对象来扩展它们的功能。这种适配器包括否定器(相当于‘非’运算)、绑定器和函数指针适配器。函数适配器用于将函数转换为函数对象,或将多参数函数对象转换为少参数函数对象。
例如:
在STL程序中,有些算法需要一个一元函数作为参数,所以一个二进制函数和一个数值可以通过一个适配器捆绑在一起,作为一元函数传递给算法。
例如:
find_if(coll.begin(),coll.end(),bind2nd(greater int(),42));
这个句子是在coll中查找第一个大于42的元素
Greater int(),实际上是,是一个2元函数。
bind2nd的两个参数要求一个是2元函数,一个是数值,结果是1元函数。
Bind2nd是一个函数适配器。
6.空间配置器
STL的内存配置器在我们的实际应用中几乎没有涉及,但是它在STL的各种容器背后默默的做了大量的工作。STL的内存配置器为容器分配和管理内存。统一的内存管理大大提高了STL库的可用性、可移植性和效率。
SGI-STL中有两种空间配置器。一个只是用C语言封装了malloc和free,另一个设计了小块内存的管理,使用内存池技术等。SGI-STL中默认的空间配置器是二级配置器。
SGI使用std:alloc作为默认配置器。
a)。Alloc将内存分配和对象构造的操作分开,分别由alloc:allocate()和:construct()负责。同样,内存释放和对象解析的操作也分别负责alloc:deallocate()和:destroy()。这样可以保证高效率,因为内存分配释放和构造分析可以根据具体类型进行优化。比如有些类型可以直接使用高效的memset来初始化或者忽略一些析构函数。Alloc还为内存分配提供了两级分配器来处理不同的情况。
b)。一级配置器直接使用malloc()和free()来分配和释放内存。第二级根据情况采取不同的策略:当所需内存超过128字节时,认为足够大,调用第一级配置器;当所需内存小于或等于128字节时,使用复合内存池来管理内存。
c)。无论allocal定义为一级配置器还是二级配置器,SGI都为其包装了一个接口,使配置的接口符合标准,即配置单位由字节变为元素的大小:
模板类T,类Alloc
类simple_alloc
{
公共:
静态T*分配(size_t n)
{
return 0==n?0:(T *)Alloc:allocate(n * sizeof(T));
}
静态T*分配(void)
{
return(T *)Alloc:allocate(sizeof(T));
}
静态void释放(T* p,size_t n)
{
如果(0!=n) Alloc:deallocate(p,n * sizeof(T));
}
静态无效解除分配
{
Alloc:deallocate(p,sizeof(T));
}
}
d)内存的基本处理工具,所有这些工具都具有commt或rollback功能。
模板类InputIterator,类ForwardIterator
前向迭代器
initialized _ copy(input iterator first,InputIterator last,forward iterator result);
模板类ForwardIterator,类T
void initialized _ fill(forward iterator first,ForwardIterator last,const T x);
模板类前向迭代器,类大小,类T
前向迭代器
uninitialized _ fill _ n(forward iterator first,ForwardIterator last,const T x)
第三,具体的容器和算法
1.所有容器都提供了一个默认构造函数和一个复制构造函数。
例如:
列表int
.
vector int ivector(l.begin()、l . end());
int array[]={1,2,3,4 };
.
set int iset(array,array sizeof(array)/sizeof(array[0]));
2.与尺寸相关的功能
size(),empty(),max_size()
3.返回迭代器的函数。
begin(),end(),rbegin(),rend()
4.比较操作
==,=,=.
向量详细解释:
Capacity(),返回向量可以容纳的元素数量。
Size(),返回向量中现有元素的数量。
赋值操作:
c1=c2将c2的所有元素分配给c1。
c.assign(n,elem);复制n elem并将它们赋给c。
c.assign(beg,end);将区间beg,end中的元素赋给c。
C1 . swap(C2);交换C1和C2元素。
互换(c1,C2);同上
元素访问
c.at(索引);
c[索引];
c . front();返回第一个元素。
c . back();
插入和删除:
c .插入(位置元素);
c .插入(位置,新要素);插入n个元素
c.insert(pos,beg,end);将所有元素插入到开始、结束间隔的位置。
c . push _ back(elem);
c . pop _ back();
c .擦除(pos);删除pos上的元素并返回到下一个元素。
c.erase(beg,end);
c . resize(num);将元素数量更改为num。如果尺寸变大,所有额外的新元素都应该以默认方式构建。
c.resize(num,elem);将元素数量更改为num。如果尺寸变大,额外的新元素是elem的副本。
c . clear();全部删除。
向量的保留和调整
Reserve只分配空间而不创建对象,大小()保持不变。Resize分配空间并用空对象填充空间。
Reserve是容器的保留空间,但它并没有真正创建元素对象。在创建对象之前,不能引用容器中的元素,所以在添加新元素时,需要使用push_back()/insert()函数。
Resize是改变容器的大小并创建一个对象。因此,调用这个函数后,可以引用容器中的对象。因此,在添加新元素时,使用operator[]运算符或迭代器来引用元素对象。
此外,这两种功能的形式是不同的。在reserve函数之后,一个参数是需要预留的容器的空间。resize函数可以有两个参数。第一个参数是容器的新大小,第二个参数是要添加到容器中的新元素。如果省略此参数,则调用element对象的默认构造函数。
vector with but deque without:capacity(),reserve();
Deque有但vector没有:push _ front (ELM),pop _ front();push_back(elem),pop _ back();
STL提供的另外两个容器,队列和堆栈,只是适配器。它们只是修改了deque的接口,变成了另一种容器类型。
列表的详细说明:
For_each(。begin(),end(),“函数”);
计数(。begin(),end(),100,季书奇);
返回等于100的对象数的值。
Count_if()取一个函数对象的参数(上面“100”的这个参数)。对象是至少有一个operator()方法的类。这个类可以更复杂。
查找(*。begin()。*end(),“找什么”);
如果没有找到指向的对象,则*的值。将返回end(),如果找到,将返回一个指向找到的对象的迭代器。
fine _ if();类似于count_if(),是find更强大的版本。
STL通用算法search()用于搜索一个容器,但它是一串元素,不像find()和find_if()只搜索单个元素。
搜索算法在一个序列中找到另一个序列的第一个出现位置。
search(A.begin(),A.end(),B.begin(),b . end());
在a中找到序列B的第一个匹配项。
为了对列表进行排序,我们使用了列表的成员函数sort(),而不是一般的算法sort()。
列表容器有自己的排序算法,因为一般的算法只能对提供对其中元素的随机访问的容器进行排序。
列表的成员函数push_front()和push_back()分别将元素添加到列表的前面和后面。您可以使用insert()在列表中的任何位置插入对象。
Insert()可以添加一个对象、一个对象的多个副本或一个范围内的对象。
成员函数pop_front()删除列表中的第一个元素,pop_back()删除最后一个元素。函数的作用是:删除迭代器指出的元素。还有另一个erase()函数可以删除一系列元素。
列表的成员函数remove()用于从列表中移除元素。
*.remove(要删除的对象);
通用算法remove()的工作方式与list的成员函数不同。通常,容器的大小不会改变。
删除(*。begin(),*。end(),要删除的对象);
使用STL通用算法stable_partition()和列表成员函数splice()对一个列表进行分区。
Stable_partition()是一个有趣的函数。它重新排列元素,使符合指定条件的元素排在不符合条件的元素之前。它维护两组元素之间的顺序关系。
Splice将另一个列表中的元素合并到一个列表中。它从源列表中删除元素。
地图详细信息:
虽然STL map和set的使用并不复杂,但还是有一些难点需要理解,比如:
为什么map和set的插入和删除效率比其他序列容器高?
为什么之前保存的迭代器不会在每次插入后失效?
为什么map和set不能像vector一样有预留功能来预分配数据?
当数据元素数量增加时(10000到20000次比较),map和set的插入和搜索速度如何变化?
C STL中的标准关联容器Set、multiset、map、multimap是一种非常高效的平衡检索二叉树:红黑树,也称为RB树。RB树的统计性能优于AVL树。
为什么map和set的插入和删除效率比其他序列容器高?
大多数人说很简单,因为关联容器不需要做内存复制和内存移动。是的,它是。map和set容器中的所有元素都存储为节点,它们的节点结构类似于链表,指向父节点和子节点。这里的所有操作都是指针交换,与内存移动无关。
为什么之前保存的迭代器不会在每次插入后失效?(相同的解决方案)
为什么map和set不能像vector一样有预留功能来预分配数据?
原则上是因为map和set中存储的不是元素本身,而是包含元素的节点。
其实只要记住map和set里面的分配器已经变了,就不要指望reserve方法了。
当数据元素增加时(10000和20000比较),map和set的插入和搜索速度如何变化?
如果你知道log2之间的关系,你就应该彻底知道答案了。在map和set中搜索使用二分搜索法,即如果有16个元素,最多需要比较4次才能找到结果,有32个元素,最多需要比较5次。一万呢?最大比较次数为log10000,最大次数为14。如果是20000个元素呢?但最多15次。
通用算法:
所有算法的前两个参数都是一对迭代器:[first,last],用来指出容器内某个范围内的元素。
每个算法的声明显示了它需要的最低级别的迭代器类型。
常用算法:
accumulate()元素累加。
相邻元素之间的差异
Adjacent_find()搜索相邻的重复元素。
二进制搜索()二分搜索法
复制()复制
Copy_backward()反向复制
Count()计数
Count_if()在特定条件下计数
Equal()判断它们是否相等。
Equal_range()确定它是否相等(返回一个上限和下限范围)
Fill()填充元素值
Fill_n()填充元素值,n次
查找()搜索
Find_if()在特定条件下进行搜索
Find_end()搜索子序列的最后一个匹配项。
Find_first_of()搜索某些元素的第一个匹配项。
For_each()对作用域中的每个元素执行一个操作。
Generate()用指定动作的运算结果填充特定范围内的元素。
Generate_n()用指定动作的运算结果填充n个元素内容。
包括()封面
inner_product()的内积
Inplace_merge()合并并替换(覆盖)
Iter_swap()元素交换
dictionary _ compare()在字典排列中进行比较。
下限()下限
Max()最大值
max_element()最大值的位置
Min()最小值
min_element()最小值的位置
Merge()合并两个序列。
Mismatch()找出不匹配的地方。
Next_permutation()获取下一个排列组合。
通用算法和功能对象
Nth_element()重新排列序列中第n个元素的左端和右端。
Partial_sort()局部排序
Partial_sort_copy()在本地排序,并复制到其他地方。
Partial_sum()局部和
分割()切割
Prev_permutation()获取前一个排列组合。
随机重排
Remove()删除一个元素(但不是删除它)
Remove_copy()移除一个元素并将结果复制到另一个容器中。
Remove_if()有条件地删除一个元素。
Remove_copy_if()有条件地删除一个元素,并将结果复制到另一个容器中。
Replace()替换一个元素。
Replace_copy()替换一个元素并将结果复制到另一个容器中。
Replace_if()有条件地替换
Replace_copy_if()有条件地替换并将结果复制到另一个容器中。
Reverse()反转元素的顺序。
Reverse_copy()反转元素的顺序,并将结果复制到另一个容器中。
旋转()旋转
Rotate_copy()旋转并将结果复制到另一个容器中。
Search()搜索子序列。
Search_n()搜索“N个连续出现”的子序列
差集
Set_intersection()交集
对称差集
Set_union()联合集
Sort()排序
Stable_partition()剪切并保持元素的相对顺序。
Stable_sort()排序并保持等价元素的相对顺序。
Swap()替换
Swap_range()替换(指定范围)
Transform()基于两个序列,交互产生第三个序列。
Unique()折叠重复的元素,使它们唯一。
Unique_copy()将重复的元素折叠缩小为唯一的,并复制到其他地方。
上限()上限
第四,注重细节:
1.auto_ptr不能用new[]生成的数组作为初始值,因为用的是delete而不是delete[]
2.就搜索速度而言,哈希表通常比二叉树快5~10倍。哈希表不是C标准库的成员。
3.在迭代器的使用中,前递增运算符(iter)比后递增运算符(iter)更受青睐。
3.迭代器有三个辅助函数:advance()、distance()和iterator _ swap()。
Advance()推进迭代器。
Distance()可以处理迭代器之间的距离。
Iter_swap()可以交换两个迭代器引用什么。
4.hasp函数makeheap()、push_heap()、pop_heap()、sort_heap()
5、/0 在string中没有特殊含义,但在一般C形式中用来标记字符串的结束。在字符串中,字符“/0”与其他字符的位置相同。string中有三个函数可以将字符串的内容转换成字符数组或C格式的字符串。
Data()以字符数组的形式返回字符串的内容。但是“/0”字符没有附加在末尾,并且返回类型不是有效的C格式字符串。
C_str()以C的形式返回字符串内容(在末尾添加/0 字符)。
Copy()将字符串内容复制到“调用者提供的字符数组”中,不添加“/0”字符。
6.在容器中使用empty,而不是检查大小是否为0;当使用new获取指针的容器时,记得在容器被销毁之前删除那些指针;千万不要把auto_ptr放到容器里。
7.尽量用vector和string代替动态应用数组;避免vector bool,它有两个问题。首先,它不是一个真正的STL容器,其次,它不包含bool类型。
8.使用迭代器时,尽量使用迭代器,而不是const_iterator、reverse_iterator和const _ reverse _ iterator使用distance和advance将const _ iterators转换为迭代器。
typedef deque int IntDeque//和以前一样
typedef int deque:iterator Iter;
typedef int deque:const _ iterator ConstIter;
IntDequed
便秘者ci;
.//让ci指向d。
ITER I(d . begin());//将I初始化为d.begin()
前进(I,距离(I,ci));//调整I以指向ci位置
9.避免修改set和multiset的键值。
10.总是让比较函数为同一个元素返回false。
11.分类和选择:
1)如果需要对vector、string、deque或array进行完全排序,可以使用sort或stable_sort。
2)如果你有一个vector,string,deque或者array,你只需要对前N个元素进行排序。你应该使用partial_sort。
3)如果你有一个vector,string,deque或者array,你需要识别第n个元素或者你需要识别前n个元素而不知道它们的顺序。第n _ element才是你要关注和调用的。
4)如果你需要把标准序列容器的元素或者数组分成符合和不符合某个标准的,你大概要找partition或者stable_partition。
5)如果你的数据在列表中,可以直接用partition和stable_partition,可以用列表的排序代替sort和stable_sort。如果你需要partial_sort或者nth_element提供的效果,你必须间接地完成这个任务。
12.如果你真的想删除什么东西,在remove这样的算法之后连接erase。移除从容器中移除元素不会改变容器中元素的数量,erase实际上是删除东西。
13.当心在指针的容器上使用类似remove的算法,在调用类似remove的算法之前,手动删除和丢弃指针。
14.尽量使用成员函数,而不是同名算法。有些容器有和STL算法同名的成员函数。关联容器提供count、find、lower_bound、upper_bound和equal_range,而列表提供remove、remove_if、unique、sort、merge和reverse。在大多数情况下,您应该使用成员函数而不是算法。这有两个原因。首先,成员函数更快。其次,与算法相比,它们与容器(尤其是关联容器)的集成更好。那是因为同名的算法和成员函数通常是不一样的。
15.在容器中使用自定义结构时,如果使用复制和赋值,该结构需要重载operator=符号;将容器比较为相等和不相等,当相等时重载运算符==符号,当不相等时重载运算符符号。例如,set、map、multiset、multimap、priority_queue等容器类需要重载的运算符符号。
16,Map/Multimap,Sets/multiset不能用push_back,push_front,因为是自动排序的。
一个集合中具有相同值的元素只能出现一次,多个集合可以包含多个具有相同值的元素。
具有相同值的元素在一个映射中只能出现一次,并且一个Multimap可以包含多个具有相同值的元素。用内部二叉树实现,容易找到。
17.有许多方法可以在字符串和数字之间进行转换。通常,使用字符串流来实现转换。例如:
#包括iostream
#包含流
#包含字符串
使用命名空间std
int main()
{
int I=0;
字符串温度;
string stream s;
//字符串被转换为数字
temp=" 1234
s温度;
s I;
cout i endl
//将数字转换为字符串
i=256
s I;
temp=s . str();
cout温度结束;
系统(“暂停”);
返回0;
}
18.对于用户定义的结构,将其放在容器中。最好不要初始化容器的内存(不要调用memset,zeromemory函数)。否则,如果结构中有指针类型的变量,就会出现问题。
19.向量的函数泄漏
定义一个
结构温度
{
char name[256];
int I;
}
向量温度向量;
在这个vect上执行pushback一些temp结构的时候,执行clear的时候会有内存泄漏吗?你能释放临时结构中的名字内存吗?
解决方法:
不,清除只是删除所有这些元素,而不是释放内存。此外,像这样定义容器时,不需要释放内存。如果这样定义,std:vector temp *pVec。你需要它。PVec- clear()后跟PVec-swap((STD:vector temp)(* PVec))。可以释放内存。
20.stl地图擦除方法的正确使用
STL的映射表中有一个erase方法可以从映射中删除一个指令的节点,没有问题。
如果再删除一个节点,就需要使用正确的调用方法。例如,下面的方法就有问题:
for(ITER ITER=map test . begin();iter!=map test . end();iter)
{
cout ITER-first : ITER-second endl;
map test . erase(ITER);
}
这是一种错误的写法,会导致未知的程序行为。原因是map是一个关联容器。对于关联容器,如果一个元素已经被删除,那么它对应的迭代器将失效,不应该再被使用;否则,将导致程序的未定义行为。
正确的使用方法:
1).删除前使用迭代器定位下一个元素。STL建议的用法
for(ITER ITER=map test . begin();iter!=map test . end();)
{
cout ITER-first : ITER-second endl;
map test . erase(ITER);
}
或者
for(ITER ITER=map test . begin();iter!=map test . end();)
{
ITER ITER tmp=ITER;
iter
ITER tmp-first : ITER tmp-second endl;
map test . erase(iterTmp);
}
2).erase()成员函数返回下一个元素的迭代器。
for(ITER ITER=map test . begin();iter!=map test . end();)
{
cout ITER-first : ITER-second endl;
ITER=map test . erase(ITER);
}
推荐书籍:
755-79000本书关注标准模板库,并研究它的容器、迭代器、函子和算法。您还可以找到特殊的容器、字符串、数字类别、国际化问题和IOStream。每个组件都有一个深刻的介绍,包括其介绍,设计,应用实例,详细的解释,陷阱,意想不到的危险,以及相关类别和功能的确切签名和定义。对基本概念有深刻见解的介绍和对一个库的全面鸟瞰会给新手带来快速的提高。
055-79000阐述了泛型编程的中心概念:概念、建模、精化,并向您展示了这些概念是如何派生出STL的基本概念:迭代器、容器、函数对象。沿着这条路线,你可以把STL想象成一个由概念(不是显式的函数或类)组成的库。你将学习它的正式结构,并获得它的潜在力量。
完整优势.
《Effective STL》阐述了如何有效地使用STL(Standard Template Library, 标准模板库)进行编程。书中讲述了如何将STL组件组合在一起,从而利用库的设计。这些内容会帮助你针对简单的问题开发出简单、直接的解决方案,并且针对复杂的问题开发出精致的解决方案。书中还描述了常见的STL使用错误,并告诉你如何避免这些错误。
《STL源码剖析》了解源码,看到vector的实现、list的实现、heap的实现、deque的实现、RB-tree的实现、hash-table的实现、set/map 的实现;你将看到各种算法(排序、搜寻、排列组合、数据移动与复制…)的实现;你甚至将看到底层的memory pool 和高阶抽象的traits 机制的实现。
STL China 网站:http://www.stlchina.org/
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。