-
顺序容器
- 虽然容器在用的时候有默认构造函数就够了。但是其实它还有几个其他的构造函数。
- 容器初始化的方式,大小和内容都可以设置。
- 放到容器里的类型,需要遵守两个约束。
- 元素类型必须支持赋值操作。比如io类的对象就不支持赋值。
- 元素类型必须可以复制。
- 比如元素是容器的时候,>中间需要空格,不知道c++11里面要不要。
-
迭代器和迭代器范围
- 迭代器有相同的接口
- 只有vector和deque支持迭代器的算术运算。只有!=和==关系运算符适用于所有的容器迭代器。
- iterator range就是一对表示一个范围的迭代器,first和last。
- 写代码的时候注意是否有元素的修改,注意迭代器是不是失效了。
-
容器内部的类型
- size_type 无符号整型,足以存储此容器类型的最大可能容器长度
- iterator
- const_iterator
- reverse_iterator 按逆序寻址元素的迭代器
- const_reverse_iterator
- difference_type 足够存储两个迭代器差值的有符号整型,可为负数
- value_type 元素类型
- reference 元素的左值类型,是 value_type& 的同义词
- const_reference 元素的常量左值类型,等效于const value_type&
-
顺序容器的操作
- 容器里面的元素,都是副本,都是拷贝过去的,你改变容器里面的值,外面的不会变。除非是引用或者指针。
- 在顺序容器中添加元素的操作。insert可以在迭代器指向的元素之前插入一个元素,也可以插入几个元素。具体怎么操作看接口。
- 所有的容器都支持用关系操作符来实现两个容器的比较。比较的规则要知道。注意:需要保证里面的元素能够比较的容器才能比较。
- 顺序容器的大小操作函数。size,resize之类的
- 容器的删除。erase
- 赋值操作会把左操作数的内容清空然后把元素加进去,而且它的迭代器都将失效。
- swap操作之后,迭代器依然会指向原来的元素,即使被交换到另外一个容器里了。因为不会有元素的删除。所以这个操作的执行速度比直接将右操作数赋值给左操作数要快。
- assign函数,重新设置容器内的元素。会先删除所有元素。可以是不同的容器类型,元素类型要兼容才行。
-
vector的自增长
- vector在空间不够的时候,会重新分配空间,所有的元素要复制过去,这个动作导致了很大的效率问题,书上说大家还是会选择用vector而不是list的原因,是因为写库的人针对vector连续储存的特性做了很多优化,这些优化会抵消掉刚刚说的浪费的情况。其中我认为这个策略的确比较好,就是vector实际分配的空间会比当前需要的空间多一些,所以不会出现添加一个新元素就分配一次空间的情况。
- capacity函数返回的是当前分配的空间可以存多少个元素。
- reserve函数,设置capacity的大小,最后capacity结果可能会大于设置的,不一定等于。
- 要知道在用完capacity空间之前,vector是不会重新分配空间的。这也就说明,那些cost也是可控制的。 c++真强大。
- 编译器重新分配的策略是,加倍当前capacity。不同的库不同的策略= =
- 这些策略的制定至少要保证vector的高效性,比如调用n次push_back,时间复杂度要低于O(n)。
-
容器的选用
- deque容器插入元素,不会使任何迭代器失效,而删除元素也只会是删的那个失效。
- 可以用list做一个缓存,然后把这段数据插入到vector里面。这个方法很巧妙。
- 一般来说,你程序里哪种操作用的多,就选适合那种操作的。
- 如果暂时判断不出选哪种策略,就把那段代码写成用迭代器操作的逻辑,这样你能很方便的从使用vector的容器修改成使用list的容器
-
再谈string
- string在某些方面也能看作是容器。
- 跟vector一样,也是连续存储的。
- 其他的啰里八嗦的东西,其实看它的文档就行了。
-
适配器,书上对这个概念的解释是:
A container adaptor takes an existing container type and makes it act like a different abstract type.
- 通俗的来说,一个容器有它的逻辑存储方式,适配器就是把这个容器里的数据复制过来,然后按照适配器的原理工作。
- stack< string , vector< string > > 这个写法好像意思是覆盖原来的stack派生。
- stack,queue,priority_queue,要知道怎么用