effective stl(容器部分总结)

还是很喜欢effective部分的书,看了好几遍,这里把stl中和容器相关的一些基本的注意的点进行介绍总结,之后对迭代器等进行总结

1 对序列容器中需要逐个删除的时候,不能像关联容器那样事先对迭代器进行++操作,因为删除一个迭代器,会使他自己无效,后面的迭代器也无效,所以应该保存删除erase返回的下一个指针的值。而关联容器中并不会导致后面的迭代器无效的情况

2 在stl中如果对容器内对象使用了new操作,一定要释放掉,因为析构函数没办法完成,这里最好使用智能指针,但是不要使用auto_ptr的指针,因为他的拷贝,会使背被拷贝的对象赋值为NULL可能导致无法预料的问题

3 如果希望减少在替换容器的类型的时候需要修改的代码,那么应该把容器进行typedef的替换,同时最好直接隐藏到一个类当中,进行使用接口进行处理

4 使用区间成员函数,比如assign,区间的构造函数,区间的insert函数,区间的erase函数,都能比循环调用单元素对应的函数好,从函数调用,元素之间赋值位置变化,还有内存的分配问题进行考虑

5 对于序列容器,list容器,还有关联容器,删除元素的使用应该选用不同的删除函数,具体参见条款9,注意这里是删除某个单独的元素,如果是直接删除一个区间的数据,那么直接利用erase就可以

6 许多string的背后使用了计数的功能,消除没有必要的内存分配和字符拷贝,提高了效率。但是如果是在多线程的情况下,那么久必须注意读写的一致性问题

7 reverse函数只有vector和string有

他可以减少内存重新分配的次数

重点需要区分一下resize和reverse两个函数

resize:强迫容器改变到包含n个元素的状态,如果比现在的size()数量小,那么将末尾的数据析构,如果大那么利用默认构造函数进行初始化

reverse:强迫容器的容量为n,和capacity()进行对应,通常导致新的内存分配。如果n比当前的容量小,vector什么都不做,string将其设为size()和n中的最大值

一般在声明容器后就进行reverse的操作,可以预见大小的情况下,之后也就可以预估迭代器是否会失效

8 string有很多的实现方式

但是基本都必须存有下面几个部分的数据

字符串的大小

内存的容量capacity

字符串的值

分配子的一个拷贝

对值的引用计数

不同的实现方式可以会使器是否有引用计数,经常需要复制,或者多线程的情况下可能有用,同时如果是小字符串,是否会进行单独的油画,创建时候的动态分配内存的数量等,详情看第15条数据

9 如果有一个 C API的函数

void dosomething(const int* pInts,size_t numInts);

void dosomething(const char* pInts);

对于vector可以直接传入&v[0],一般不建议传入v.begin()因为他毕竟是一个迭代器,但是传入的时候需要判断容器是不是空的

对于string有一个专门的函数,s.c_str(),不需要判断是否为空

一般传入后,最好设为只读模式,如果进行了增删操作,那么可能会直接影响了之前的容器,导致一些不可预见的影响

如果是C函数初始化容器,都可以利用vector进行一个中间的转存的操作,详情见16条款

10 如果希望将vector,string中的一些多余的容量进行删除,erase主要是删除了容量的大小,但是并没有减少容量,为了压缩到适当的大小利用swap的方法

vector<Contestant>(V2).swap(V2)

string s; string(s).swap(s)

先通过创建临时变量,只会拷贝存在的元素,然后再交换

同时注意:并不是说之后的内存就刚好是元素的内存和,可能也会有一定的保留

同时:之前的迭代器和,指针,引用之类并不会失效

11 vector中最好不要使用vector<bool>的容器,因为他并不是一个真正的容器,只是近似于一个容器。他是没有办法通过operator []取位置进行操作的。因为一个bool在实现的时候是按位进行存储的,只占有一个二进制位。而为了适配[]操作,封装了一个适配器返回的是一个适配类。所以很多麻烦

如果一定要用bool的容器,那么建议使用deque<bool> (相对于vector函数只是没有reverse和capacity操作)和bitsize(也是紧凑存储,事C++标准库中的函数)

12 在关联容器中 有两个概念,相等和等价

非成员函数的find函数一般是利用相等,operator ==基于数据的值是否相等eaqul_to函数

非成员函数的insert操作,因为要判断,是否有相同的key了,所以主要是对排序数据中的位置进行判断的,在其中的等价关系主要是通过operator < 进行判断的,less函数

每个标准容器利用用户自己定义的key_comp进行判断,默认的函数是less函数,可以自己设定,确定了之后只要利用成员函数进行访问,那么就能够将比较进行统一了。

而且最好在和排序相关的关联容器中使用等价的概念

因为如果相等的情况下插入两个其实等价的数据,但是在排序的时候又没办法分开排序,那么就不能按确定的方式访问key的value值了,类似于multiSet等

但是这里主要是提到了带排序的关联容器,对于不是标准的关联容器:

hash_set hash_multiset hash_map hash_multimap

这些关联容器并不是按照排序方式进行存储的

他们的比较函数就是equal_to

13 复习一下traits的应用

14 如果想打印一个容器中的值,可以用copy函数讲值放入一个输出流中

copy(ssp.begin(),ssp.end(),ostream_iterator<string>(count,”\n”))

还有一个需要注意的地方就是在传入一些比较函数的时候其实传入的需要的是一个类型,而不是函数指针,如果是函数指针,直接声明一个函数就可以了。。。需要注意,如果是一个类型

那么一般选择的是一个struct类型后创建一个函数

struct Differ{

template<typename ptrtype>

bool operator()(ptrtype p1,ptrtype p2)

{

return *p1 < *p2;

{

}

调用的时候 set<string* , Differ> ssp

15 感觉21条建议真的是很晕啊,看了几遍才理清楚

主要是容器中虽然有一个等价的判断函数比如compare但是最后判断是否是等价还有一个外层的判断

!(compare(a1,a2)) && !(compare(a2,a1))

如果compare函数将两个相等的数判断为相等,那么最终会导致说这两个数不等价,错误

所以对相等的数,compare应该返回false,其实这里的compare应该理解为 一个值是否在另一个值的前面,如果两个值相等,那么他的值当然没有位置的关系,所以应该返回false

16 对于set map类型中如果需要修改对应的key

在map中类型是pair<K,V>,其中K是const类型,所以是不允许直接修改的

在set中元素不是const的,因为类型可能是定义的struct或者 class的类型,在排序的过程中,根据某一元素进行排序,那么在修改的时候他是不能够修改的,但是对于别的部分,是可以进行修改的。

因为如果直接修改,可能会影响之前的排序情况

如果一定要进行改变,最好的是复制元素,修改,删除后重新插入

17 在考虑排序的vector的过程中:

因为map中是按照平衡二叉树进行存储的,如果只是想要提高查询的速度,那么选用散列的容器(常数时间)远远好于标准容器的对数时间,但是如果散列表比较小,可能会使查找的性能比较差

同时在map的存储中因为还有一些指针的额外开销,同时作用兄弟在无力上的存储也不相邻。所以如果量很大,比如跨越了多个内存页面的情况下可能会相对而言比较慢。

相对于排序的vector中,如果采用binary_search可能会更快,但是因为是vector的情况,所以必须要求数据的增删的操作很少,同时还得模拟pair 的一些操作,这里一个注意的地方就是,map中的key是const的,但是在vector中进行模拟的时候是不能定义为const,因为会有很多的拷贝操作等

18 对于map的操作,[]操作有不同的意思,如果key在原来的数据结构中没有,那么对应时插入操作,如果已经有了,那么对应的就是修改操作

为了效率高,

如果,确定知道是插入,最好利用insert操作。因为如果是[],是先插入一个构造函数对应的pair数据,然后再进行修改的数据,不如直接插入

如果是修改操作,那么就是直接进行[],因为如果是利用insert,是先将值[]修改了后insert

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2025-01-04 02:25:36

effective stl(容器部分总结)的相关文章

Effective STL -- 容器

01.慎重选择容器类型 选择容器原则:需要考虑元素的排序情况,是否与标准相符,迭代器能力,元素布局,与C的兼容性,查找速度,引用计数,插入删除对事物语义的支持,某些操作是否会使迭代器无效,内存分配策略. vector 需要使用随机迭代器 容器中布局需要与C兼容 deque 需要使用随机迭代器 当大多数插入在头部和尾部时 在尾部插入不会是迭代器,指针,引用变为无效 string 需要使用随机迭代器 介意使用引用计数计数,避免使用string,rope.string不可行 介意在容器上使用swap导

Effective STL 第7条:如果容器中包含了通过new操作创建的指针,切记在容器对象析构前将指针delete掉

STL中的容器相当"聪明",它们提供了迭代器,以便进行向后和向前的遍历(通过begin.end.rbegin等):它们告诉你所包含的元素类型(通过它们的value_type类型定义):在插入和删除的过程中,它们自己进行必要的内存管理:它们报告自己有多少对象,最多能容纳多少对象(分别通过size和max_size):当然,当它们自身被析构时,它们自动析构所包含的每个对象. 有了这么"聪明"的容器,许多程序员不再考虑自己做善后清理工作.更糟糕的是,他们认为,容器会考虑为

Effective STL 条款1:仔细选择你的容器

条款1:仔细选择你的容器 了解各种容器的实现方法,知道各种容器的内存管理方式.各种操作所对应的底层操作,然后根据需要选择恰当的容器. 对于容器的分类: 标准STL序列容器:vector,string,deque和list 标准STL关联容器:set,multiset,map和multimap 非标准序列容器:slist(单向链表)和rope(重型字符串--不懂) 非标准关联容器:hash_set,hash_multiset,hush_map和hash_multimap vector == str

Effective STL 第1条:慎重选择容器类型

C++提供了几种不同的容器供我们选择,这里简单回顾一下: 1.标准STL序列容器:vector.string.deque和list. 2.标准STL关联容器:set.multiset.map.和multimap. 3.非标准序列容器slist和rope.slist是一个单向链表,rope本质上是一"重型"string. 4.非标准关联容器hash_set.hash_multiset.hash_map和hash_multimap. 5.vector<char>作为string

C++:标准string或者STL容器不含virtual析构函数,所以不应该被继承——摘自Effective C++中文版第三版P42

即使class完全不带virtual函数,被“non-virtual析构函数问题”给咬伤还是有可能的.举个例子,标准string不含任何virtual函数,但有时候程序员会错误的把它当做base class: 1 // 馊主意,std::string有个non-virtual析构函数 2 class SpecialString: public std::string{ 3 ... 4 }; 乍看似乎无害,但如果你在程序任意某处无意间将一个pointer to SpecialString转换成一个

Effective STL 中文版(大全)

Effective STL 中文版(大全) 作者:winter 候捷说,对于STL,程序员有三个境界,开始是使用STL,然后是理解STL,最后是补充STL.Effective STL是一本非常好的书,帮助你更好的理解STL,其作者就是<Effective C++>一书的作者.如果你已经初步了解了STL的容器.迭代器.算法和函数,而又想更好的了解STL,那么<Effective STL>是你的最佳选择. 还有一部分没有找到链接,如果再找不到我会自己试着翻译一下:) 前言 容器 条款1

迅速读懂:Effective STL (五)

这是<Effective STL>笔记最后一期,不能涵盖全部内容,书后仍然有些附加内容,不在附加,有兴趣可以找原书来读读,一则是区域设置后的忽略大小写比较,另一则是MSVC4-5编译器下STL注意事项 条款41:了解使用ptr_fun.mem_fun和mem_fun_ref的原因 函数和函数对象总使用用于非成员函数的语法形式调用.mem_fun带有一个到成员函数的指针,pmf,并返回一个mem_fun_t类型的对象.这是一个仿函数类,容纳成员函数指针并提供一个operator(),它调用指向在

Effective STL读书摘要(一)

一直在用STL,认为对STL也有一些理解,比如比较函数怎么写,什么情况下用什么容器效率高,但是当你读过Effective STL之后才知道这远远不够,之前的代码还有很多可以优化的空间,下面我会罗列一些映像比较深的点,比较偏向代码因为这样可以方便以后的调用.这里是到Item29,余下的留下次看. 1) 检查容器是否为空 if(c.empty()){}   better than if(c.size()==0){} 2)如果能用批量操作函数就不要用循环来做 批量操作可以提高效率,要有能用批处理尽量批

STL容器简介

C++标准定义了一系列的容器的共通要求,适用于所有的STL容器,然而由于C++11带来了容器的多样化,因此可能出现若干例外. ?初始化: 每个容器都提供了一个default构造函数,一个copy函数和一个析构函数 ? ? ?