

array呢?为了实现数组复制的操作。由于array不支持扩展长度,所以定义的时候必须也指定大小。#include
#include
int main()
{
std::array<int, 3> a;
std::array<int, 3> b = a; // 数组复制
std::array a = {1, 2} ,那么前两个是1,2,剩下的用0初始化。如果不进行初始化,那么内部值初始化为乱值,即随机初始化。std::array::value_type // 就是int ;siz _type:大小的类型,实际就是size_t。at方法相对[]方法对索引超过数组大小可以让程序崩溃,并且给出提示;而[]方法可能会崩溃(无提示),也可能访问非法内存,所以没有at方法好。front/back返回数组第一个/最后一个元素。data返回数组成员类型的指针,指向数组中的第一个元素,跟内建数组的数组名差不多的功能。同时这个接口也是为了和接受内建数组类型的函数接口兼容,比如如下代码:void fun(int* ptr)
{}
int main()
{
std::array<int, 3> a = {1, 2, 3};
fun(a.data()); // a.data()得到int*类型,指向a的第一个元素
}
注意:并不是所有的容器都有data接口,后面可以看到vector也有data接口,实际上只有容器中的元素在内存中连续存储的时候才会有data接口,这个很好理解,和数组一样,这样提供了data接口就可以使用指针连续访问了。而如果不是连续保存的,那么返回data也没有意义,后面无法用它进行访问其他元素。
empty:实际上编译期就确定了,是否为空size:也是编译期确定,大小max_size:也是编译器确定,跟size一样。为啥还这样呢?这是为了统一接口,比如vector中这些量就不一样了,所以就是为了接口统一。填充与交换:填充很简单,就是把一个array全部填充成某个值。交换是交换两个array的数值。但是注意,这两个操作的成本是非常高的,因为它内部就是一个数组;而vecotr交换操作成本就很低,因为它内部是一个指针指向一个数组。
迭代器


array都一样。capacity:容量reserve:实现分配好容量,防止填充的时候因为容量不够重新开内存然后拷贝再插入。shrink_to_fit:构造完vector之后,知道不会再往里面填充数据了,所以就可以把buffer的一部分内存释放掉了。vector中维护的是一个buffer指针,所以交换的时候只需要把指针交换,然后把cap/size也交换一下就可以了,存储在buffer中的数据不需要交换,因此性能高。push_back和emplace_back在内建数据类型上差别不打,但是在一些复杂数据类型,比如自定义对象、string等会有性能上的差别。push_back:先构造对象,然后把构造的对象移动或者复制到buffer中。implace_back:直接在buffer中构造对象,因此性能更高。insert:在某个位置插入,然后把这个位置后面的元素全部向后移动,这就需要移动后面的所有元素,所以比较慢。emplace:差别和push_back/emplace_back一样??疑问:我以为是在某个位置替换元素,具体使用的时候再查一下是什么意思吧pop_back:把最后的元素删掉就行erase:把某个元素删除,然后后面的元素全部前移clear:把整个vector清空vector(之前举过这个例子),但是在for循环中执行了push_back操作,此时end迭代器其实就失效了。如果push_back超过了vector的容量,此时会拷贝buffer中数据到另一个位置,此时begin迭代器也会失效。
vector是连续内存存储的,所以使用a[2]这种操作直接把buffer指针偏移2即可访问。而list则需要遍历元素,只有到了当前元素,才知道下一个元素在哪,到了下一个元素的位置,才知道下下个元素在哪,所以随机访问需要从头一直往后访问。因此list并没有提供[]这种随机访问的接口。pop_front消耗很低,这个和链表结构也是相关的。splice就是把一个list插入到另一个list的某个位置,也是由于链表结构,消耗低。list每个位置需要存储3个元素,成本太高。list是支持size属性的,原因是它内部还存储了一个size变量来统计链表的大小。但是forward_list为了降低成本,把size也去掉了。
deque是vector和list的折中:注意下图的前边和后边是白色,代表分配了内存但是并没有存储元素。但看最后一个长条的话,可以发现它就是vector的典型实现。
但是上图只是一个布局示意图,真正在实现的时候,可能如下图所示,也就是在一个数组中存储了指针,这些指针指向各个小的数组。

push_back/push_front较快:以push_back为例(push_front类似),看上图:
vector没满,那么直接在最后出入元素即可,性能和普通vector一样。vector满了,那么需要再新开辟一个vector,然后在里面插入数据;然后还需要维护一下左边的链表,把最后一个指针指向新开辟的小的vector。这里可以发现,这样并不会复制原来的那些小的vector,因此它的性能比vector要高。vector里,除以6取余得到在这个小的vector里的索引,这样就可以访问了。由于这个过程只设计数值计算,没有过多的内存访问操作,所以它的性能相对较高。但是相比vector还是没法比的。vector里面的内容都需要移动,所以是非常慢的。

