文章目录
完整掌握标准库顺序容器的知识
一个容器就是一些特定类型对象的集合。
顺序容器(sequential container)为程序员提供了控制元素和访问顺序的能力
1. 顺序容器的概述
1.1 确定使用哪种顺序容器
选择容器的基本规则
- 除非你有很好的理由选择其他容器,否则应该使用vector
2. 容器库概述
2.0.1 对容器可以保存的元素类型的限制
2.1 迭代器
2.1.1 迭代器的范围
一个迭代器范围(iteration range)是由一对迭代器表示,两个迭代器分别同时指向同一个容器中的元素或者是尾元素之后的位置(one past last element)。这两个迭代器通常被称为begin 和 end 或者 first 和last
它们标记了容器中元素的范围
迭代器范围中的元素包含first所表示的元素以及从first开始到last之间的所有元素。
这总元素范围被称为左闭合区间(left-inclusive interval)
标准数学描述为: [begin,end)
2.1.2 使用左闭合范围蕴含的编程假设
2.3 容器类型成员
2.4 容器定义和初始化
每个容器类型都定义了一个默认构造函数
2.4.1 将一个容器初始化为另一个容器的拷贝
拷贝的两种方法:
- 直接拷贝整个容器
- 拷贝一个 迭代器对 指定的元素范围
2.4.2 列表初始化
2.4.3 与顺序容器大小相关的构造函数
2.4.4 标准库array具有固定大小
定义一个array时,除了定义元素类型,还要指定容器大小
array<int, 42> //类型:为保存42个int的数组
array<string, 10> // 类型: 保存10个string的数组
使用array类型,必须同时指定元素类型和大小
array<int, 10>::size_type i; //
2.5 赋值和swap
赋值运算符将左边容器中所有的元素替换为右边容器中元素的拷贝:
c1 = c2; //
2.5.1使用assign(仅顺序容器)
- 赋值运算符要求左右两边的运算对象具有相同的类型。
- 顺序容器(除array外)定义了一个名为assign的成员,允许我们从一个不同但相容的类型赋值,或者从一个容器的子序列赋值
assign实现将一个vector中的一段char*值赋予一个list中的string:
list<string> names;
vector<const char*> oldstyle;
names = oldstyle;// 错误,容器类型不匹配
names.assign(oldstyle.cbegin(), oldstyle.cend());//正确,将const char* 转换为string
2.5.2 使用swap
swap操作交换两个相同类型容器的内容
vector<string> svec1(10);
vectot<string> svec2(24);
swap(svec1, svec2);
2.6 容器大小操作
size
empty
max_size
2.7 关系运算符
2.7.1 容器的关系运算符使用元素的关系运算符完成比较
3. 顺序容器操作
顺序容器和关联容器的不同之处在于两者组织元素的方式
3.1 向顺序容器添加元素
3.1.1 使用push_back
将一个元素追加到一个vector的尾部
//从标准库输入读取数据,将每个凡此放到容器尾部
string word;
while(cin >> word)
container.push_back(word);
3.1.2 使用push_front
将元素插入到容器头部
list<int> ilist;
for(size_t ix = 0; ix != 4; ++ix)
ilist.push_front(ix);
3.1.3 在容器的特定位置添加元素
insert成员提供了更一般的添加功能,允许在容器中任意位置插入0个或者多个元素
insert函数将元素插入到迭代器所指的位置之前
slist.insert(iter, "hello!"); //将"hello!"插入到iter之前的位置
某些容器不支持push_front 操作,但对insert操作没有类似的限制
3.1.4 插入范围内元素
insert函数将指定数量的元素添加到指定位置之前,这些元素按指定初始值初始化:
svec.insert(svec.end(), 10, "Anna");//将10个元素插入到svec末尾,并将所有元素初始化为string"Anna"
//将给定范围的元素插入到指定位置之前
vector<string> v = {"a", "b", "c", "d"};
//将v最后两个元素添加到slist的开始位置
slist.insert(slist.begin(), v.end() - 2, v.end());
3.1.5 使用insert的返回值
使用insert的饭hi子,可以在容器的一个特定位置反复插入元素
list<string> lst;
auto iter = lst.begin();
while(cin >> word)
iter = lst.insert(ite, word);
3.1.6 使用emplace操作
emplace_front
emplace
emplace_back
这些操作构造而不是拷贝元素
调用push和insert成员函数时,我们将元素类型的对象传递给它们,这些对象被拷贝到容器中。
当调用emplace成员函数时候,则将参数传递给元素类型的构造函数。
emplace成员使用这些参数在容器管理的内存空间中直接构造元素。
c.emplace_back("a", 32, 2);
c.push_back("a", 32, 2);//错误,没有接受3个参数的push_back版本
c.push_back(Sales_data("a", 32, 2));//正确,创建临时Sales_data对象传递给push_back
3.2 访问元素
3.2.1 访问成员函数返回的是引用
3.2.2 下标操作和安全的随机访问
下标运算符接受一个下标参数,返回容器中该位置的元素的引用
3.3 删除元素
3.3.1 pop_front 和pop_back成员函数
这些操作返回void
3.3.2 从容器内部删除一个元素
3.3.3 删除多个元素
3.4 特殊的forward_list操作
3.5 改变容器大小
resize来增大或缩小容器
3.6 容器操作可能使迭代器失效
3.6.1 编写改变容器的循环程序
3.6.2 不要保存end返回的迭代器
4. vector 对象式如何增长的
vector和string通常会分配比新的空间需求更大的内存空间
4.0.1 管理容量的成员函数
capacity | reserve |
---|---|
容器在不扩张内存空间的情况下可以容纳多少个元素 | 允许我们通知容器准备保存多少个元素 |
4.0.2 capacity 和size
区别:
capacity: 在不分配新的内存空间的前提下它最多可以保存多少元素
size: 它已经保存的元素的数目
vector<int> ivec;
cout << "ivec : size:" << ivec.size() <<
"capacity:" << ivec.capacity() << endl;
for (vector<int>::size_type ix = 0; ix != 24
{
ivec.push_back(ix);
}
cout << "ivec : size:" << ivec.size() <<
"capacity:" << ivec.capacity() << endl;
输出结果:
5. 额外的string 操作
5.1 构造string 的其他方法
5.1.1 subsr 操作
5.2 改变string的其他方法
5.2.1 append 和replace函数
append | replace |
---|---|
在string末尾进行插入操作 | 调用erase和insert 的一种简写形式 |