标准库容器是特定类型对象的集合,类型几乎没有限制,容器一般都定义在同名的头文件中,都是类模板,少部分还要额外元素信息。
容器类型上的操作形成了一种层次:
- 通用操作:适用于所有容器类型。
- 特有操作:每种容器类型特有。
- 顺序容器特有
- 关联容器特有
- 无序容器特有
- 小众操作:适用于小部分容器,如string特有。
类型别名
```cpp iterator //读写迭代器 const_iterator //只读迭代器 size_type //无符号,足够保存容器大小 difference_type //有符号,保存迭代器距离 value_type //元素类型 reference //元素左值类型,等价于value_type&,如int&引用。 const reference //元素const左值类型,例如const int&
list
<a name="xsvST"></a>
## 构造函数
```cpp
C c; //默认构造函数,构造空容器
C c1(c2); //构造c2的拷贝,也就是c1
C c1 = c2; //如果是array还必须大小相同
C c(b, e); //构造两个迭代器b、e之间的拷贝,array不支持
//容器之间类型可以不同,元素类型也可以不同(能转换)
C c{a, b, c...}; //列表初始化,隐含指定了容器大小。
C c = {a, b, c...}; //如果是array,数量=容器大小,数量不能超,少了值初始化(默认构造)。
//只有顺序容器(除array)构造函数才接受大小参数
C seq(n); //n个元素,值初始化,元素类型必须支持默认初始化,explicit
C seq(n, t); //n个值为t的元素
/********************例子************************/
list<string> ls;
vector<const char*> vcc;
list<string> ls1(ls); //正确,类型和元素类型要匹配
deque<string> ds(ls); //错误:容器类型不匹配
vector<string> vs(ls); //错误:容器类型不匹配
list<const char*> lcc; //错误:元素类型不匹配
forward_list<string> fls(vcc.begin(),vcc.end()); //正确,元素可转换。
array<int, 10> ial; //10个默认初始化的int
array<int, 10> ia2 = (0,1,2,3,4,5,6,7,8,9); //列表初始化
array<int, 10> ia3 = {42}; //ia3[0]为42, 剩余元素为0
vector<int> ivec(10 , -1); //10 个 int 元素,每个都初始化为-1
list<string> svec(10,"hi!"); //10 个 strings; 每个都初始化为“hi!"
forward_list<int> ivec(10); //10 个元素,每个都初始化为 0
deque<string> svec(10); //10 个元素,每个都是空string
array<int, 10>::size_type i; //array必须指定元素类型、数量
array<int>::size_type j; //错误:array<int>不是一个类型
赋值
//赋值:元素类型必须相同,会让c1的内部迭代器、指针、引用失效
c1 = c2; //赋值替换:c1的元素替换为c2
c1 = {a, b, c...}; //赋值替换:c1的元素替换为列表元素,array不适用。
//赋值:仅适合顺序容器,元素类型能转换即可。
seq.assign(b, e); //范围替换,b、e不能指向seq
seq.assign(il); //赋值替换:il是初始化列表
seq.assign(n, t); //赋值替换:n个值为t的元素
swap
//交换:不会让a的内部迭代器、引用、指针失效,但是string、array的会失效。
//交换只是改变a、b数据结构,并未拷贝,所以比拷贝赋值快得多。
//string、array是真正拷贝元素,所以上面的会失效。
a.swap(b); //a、b元素交换,类型必须相同,早期是这个成员函数版本。
swap(a, b); //同上等价,推荐使用这个。
iterator first = a.begin();
swap(a, b); //first没有失效,但是first指向了b.begin()
大小
c.size(); //size_type,元素数目,不支持forward_list
c.max_size(); //size_type,可保存最大数目
c.empty(); //是否空
插入、删除
//array不支持,不同容器,这些接口会不同。
c.insert(args) //args拷贝进c
c.emplace(inits) //inits构造C中的一个元素
c.erase(args) //删除args指定元素
c.clear() //清空容器,返回void
关系运算
//容器必须相同,元素必须相同。
//实质:元素逐个进行关系运算,所以元素必须支持相应的关系运算,可参考string的关系运算。
==, != //容器是否相等、不相等,所有容器都支持
< , <=, >, >= //无序、关联容器不支持
a == b //true:大小相同 && 元素数量相等
a <= b //逐个运算,a的全部元素都<=b元素。
vector<int> v1 = {1, 3, 5, 7, 9, 12};
vector<int> v2 = {1, 3, 9};
vector<int> v3 = {1, 3, 5, 7 };
vector<int> v4 = {1, 3, 5, 7, 9, 12};
v1 < v2 //true: vl和v2在元素[2]处不同:vl[2]小于等于v2[2]
v1 < v3 //false: 所有元素都相等,但v3中元素数目更少
v1 == v4 //true: 每个元素都相等,且vl和v4大小相同
v1 == v2 //false: v2元素数目比vl少
获取迭代器
迭代器范围(range)是标准库的基础,由 [ begin、end ) 组成,注意是左闭右开区间,并没有包含end。为什么用左闭合,因为:
- begin == end,为空。
- begin != end,迭代结束标记 ```cpp c.begin(), c.end() //首尾迭代器,尾是指向最后一个元素的后面。 c.cbegin(), c.cend() //只读首尾迭代器。
list
<a name="hJoVe"></a>
## 反向容器
```cpp
//forward_list不支持
reverse_iterator //按逆序寻址元素的迭代器
const_reverse_iterator //上面的const版
c.rbegin() //返回指向尾元素的迭代器
c.rend() //返回指向首元素前面位置的迭代器
c.crbegin(), c.crend() //上面的const版