C++Primer 笔记(2)

来源:互联网 发布:淘宝如何代销产品 编辑:程序博客网 时间:2024/05/02 14:22
 

顺序容器(sequence container)拥有由单一类型元素组成的一个有序集合。
两个主要的顺序容器是list和vector。第三个顺序容器为双端队列deque,它对于首元素的有效插入和删除提供了特殊的支持。
关联容器(associative container)支持查询一个元素是否存在,并且可以有效地获取元素。两个基本的关联容器是map(映射)和set(集合)

vector表示一段连续的内存区域,每个元素被顺序存储在这段内存中。
一个deque也表示一段连续的内存区域,但是,与vector不同的是,它支持高效地在其首部插入和删除元素。他通过两级数组结构来实现,一级表示实际的容器,第二级指向容器的首和尾。
list表示非连续的内存区域,并通过一对指向首尾元素的指针双向链接起来,从而允许向前和向后两个方向进行遍历。它对随机访问的支持并不好:访问一个元素需要遍历中间的元素。另外,每个元素还有两个指针的额外空间开销。

选择顺序容器类型的一些准则:
1、如果我们需要随机访问一个容器,则vector 要比list 好得多
2、如果我们已知要存储元素的个数,则vector 又是一个比list 好的选择
3、如果我们需要的不只是在容器两端插入和删除元素,则list 显然要比vector 好
4、除非我们需要在容器首部插入和删除元素,否则vector 要比deque 好

list 以简单方式增长:每当一个新对象被插入到list 中时,插入处的两个元素的前指针和后指针被重新赋值为指向新对象。新对象的前后指针被初始化为指向这两个元素。list 只占有其包含的元素所必需的存储区。额外的开销有两个方面:与每个值相关联的两个附加指针,以及通过指针进行的间接访问。

一个需要动态增长的vector 必须分配一定的内存以便保存新的序列、按顺序拷贝旧序列的元素以及释放旧的内存。而且,如果它的元素是类对象,那么拷贝和释放内存可能需要对每个元素依次调用拷贝构造函数和析构函数。

为了提高效率,实际上vector 并不是随每一个元素的插入而增长自己,而是当vector 需要增长自身时,它实际分配的空间比当前所需的空间要多一些,也就是说,它分配了一些额外的内存容量,或者说它预留了这些存储区。

容器的容量是指在容器下一次需要增长自己之前能够被加入到容器中的元素的总数(容量只与连续存储的容器相关)。capacity()操作。
容器的长度是指容器当前拥有元素的个数。size()操作。

容器的比较是指两个容器的元素之间成对进行比较.如果所有元素相等而且两个容器含有相同数目的元素,则两个容器相等,否则它们不相等.

容器的定义必须符合:
1、元素类型必须支持等于操作符
2、元素类型必须支持小于操作符
3、元素类型必须支持一个缺省值

迭代器(iterator) 提供了一种一般化的方法,对顺序或关联容器类型中的每个元素进行连续访问.

iterator 算术论算只适用于vector 或deque ,而不适用于list ,因为list 的元素在内存中不是连续存储的.

容器对象也可以用"由一对iterator 标记的起始元素和未元素后一位置之间的拷贝"来初始化.

删除容器内元素的一般形式是一对erase()方法:一个删除单个元素,另一个删除由一对iterator 标记的一段范围内的元素.删除容器末元素的简短方法由pop_back()方法支持.

pop_back()方法删除容器的末元素——它不返回元素只是简单地删除.

把所有容器类型的公共操作抽取出来,形成一个通用算法集合,它能够被应用到全部容器类型以及内置数组类型上。这组通用算法被称作泛型算法。

string类支持的find()函数:它返回匹配子串的第一个字符的索引位置,或者返回一个特定的值。
find_first_of()函数查找与被搜索字符串中任意一个字符相匹配的第一次出现,并返回它的索引位置。

栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区。里面的变量通常是局部变量、函数参数等。先进后出。
堆,就是那些由new分配的内存块,它们的释放编译器不去管,由应用程序控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。先进先出。
void fn(){int *p = new int[5];}

同一类型的两个栈可以比较相等、不相等、小于、大于、小于等于以及大于等于关系,只要底层元素类型支持等于和小于操作符即可。对于这些操作,栈中元素被依次比较、第一队不相等的元素决定了小于或大于关系。

队列(queue)抽象体现了先进先出(FIFO)的存储和检索策略。进入队列的对象被放在尾部,下一个被取出的元素取自队列的首部。
两种队列:FIFO队列和priority_queue(优先级队列)
priority_queue允许用户为队列中包含的元素项建立优先级。他没有把新元素放在队列尾部。而是放在比他优先级低的元素前面。

指针作为参数和reference作为参数:
当函数必须修改参数或当参数是一个很大的object,以pass-by-value的方式来传递可能会缺乏效率时,我们就使用pointer或reference作为参数。如果只是为了效率因素而采用reference作为参数,那么最好将参数声明为const。
指针比较适合用来"不指向任何对象",或在不同的时间指向不同的对象。
使用"reference参数"的好处是,调用者不需明白传递参数地址,函数中也不必使用(解引用)操作符来取得参数值。

如何从一个函数中传出多个数值:
要从一个函数中传出多个数值,方法之一是把所有返回值设为reference参数。
优点:调用者不必明白传递参数地址,并得以控制对象储存空间的分配操作。如果函数希望对于将被返回值有动态分配的自由度,那么上述做法便存在缺点。此时,应该采用一个reference,以它代表一个指针参数。
另一种方法是返回一个pair对象,或是一个合成结构。

若一个函数被指定为inline(内联)函数,则它将在程序中每个调用点上被"内联地"展开。

一般地,inline 机制用来优化小的、只有几行的、经常被调用的函数。

对于同一程序的不同文件,如果inline函数出现的话,其定义必须相同

指向函数的指针可以被用来调用它所指向的函数。调用函数时,不需要解引用操作符。无论使用函数名直接调用函数,还是用指针间接调用函数,写法是一样的。

指向C 函数的指针与指向C++函数的指针类型不同。记住,对于函数指针的初始化或者赋值,只有当被赋值的指针类型与赋值操作符右边的指针或函数完全匹配时,初始化或者赋值才是合法的。因此,指向C 函数的指针不能用指向C++函数的指针初始化或赋值,反之亦然。