C++ 学习笔记(9)顺序容器、容器适配器
2018-01-28 17:35
661 查看
C++ 学习笔记(9)顺序容器
参考书籍:《C++ Primer 5th》API:容器库
9.1 顺序容器概述
string 和 vector 元素保存在连续的内存空间中。所以用下标计算地址时非常快。
forward list 的设计目的是达到与手写单项列表数据结构相当的性能。
9.2 容器库概述
class A { public: string name; A(string str) { name = str; } }; void main() { vector<A> v1(2, A("abc")); // 使用构造函数初始化所有元素。 }
9.2.1 迭代器
迭代器范围(iterator range):由两个迭代器表示,指向同一容器元素或元素之后的位置(begin 和 end)。9.2.3 begin 和 end 成员
vector<A> v1; auto it1 = v1.begin(); // it1 是 vector<A>::iterator 类型 auto it2 = v1.cbegin(); // it2 是 vector<A>::const_iterator 类型
9.2.4 容器定义和初始化
将容器创建为另一个容器的拷贝有两种方法:
直接拷贝:要求容器类型相同,其元素类型也相同。
由迭代器指定元素范围:不要求容器类型相同,元素类型也可以不同(但能要转换)。
list<string> str1 = { "abc","jjj","2333" }; vector<const char *> ccp = { "fuck","that","shit" }; // 直接拷贝 list<string> str2(str1); // 正确,容器类型相同,元素类型相同。 vector<string> vec(str1); // 错误,容器类型不同。 list<const char *> ccp2(ccp); // 错误,元素类型不同。 // 迭代器拷贝 forward_list<string> words(ccp.begin(), ccp.end()); // 正确,容器类型可以不同,元素类型不同但可以转换。
array具有固定大小,初始化时需要同时类型和指定大小。
内置数组无法进行拷贝或对象赋值,但是array可以。
int digs[3] = { 1,2,3 }; int cpy[3] = digs; // 错误,内置数组不支持拷贝或赋值 array<int, 3> digits = {1,3,5}; array<int, 3> copy = digits; // 正确,但要求类型要完全相同
9.2.5 赋值和swap
swap交换两个相同类型容器的内容。元素本身并没有交换,交换的是两个容器的内部数据结构(即不对元素拷贝、插入、删除)。这样指向内容迭代器、引用和指针都在swap操作后不会失效。
swap交换两个array会真正交换元素(迭代器、指针和引用指向的位置不变,但是内容变了,所以是错误的),交换的时间和array中元素数目成正比。
9.2.6 容器大小操作
forward_list 支持max_size 和 empty,但不支持size。9.2.7 关系运算符
类似string:两个容器元素对应相等时,容器相等。
容器大小不同,但小的都对应相等时,数目少的大于数目多的。
两个容器比较结果也取决于第一个不同的元素比较结果。
9.3 顺序容器操作
9.3.1 向顺序容器中添加元素
对于vector和string,除了尾部,其他位置添加元素都需要移动元素。还可能引起整个对象存储空间重新分配。
对于deque,除了首尾,都要移动元素。
insert返回的是指向新插入元素的迭代器。
当用一个对象来初始化容器时,或将一个对象插入到容器(push或insert),实际上放入到容器中的对象值的拷贝,而非本身。
使用emplace操作是构造而非拷贝。直接在容器中构造,不会产生临时对象。
class A { public: string name = "nothing"; A() = default; A(string str) { name = str; } }; void main() { vector<A> vecA; vecA.emplace_back("shit"); // 在容器内部中直接构造元素,调用了A(string str)的构造函数。 vecA.emplace_back(); // 添加了使用默认构造函数的对象。 system("pause"); }
9.3.2 访问元素
front、back、下标、at:返回的都是引用。
vector<string> svec; cout << svec[0]; // 运行错误。 cout << svec.at(0); // 抛出out_of_range异常。
9.3.3 删除元素
erase删除元素后,返回指向删除元素后位置的迭代器。
9.3.4 特殊的forward_list操作
在删除一个元素时,会影响到前一个元素的信息(即指向下一个元素的地址)。要删除一个元素,就要在前一个元素调用erase_after。
9.3.5 改变容器大小
9.3.6 容器操作可能使迭代器失效
容器添加元素:vector 或 string:
重新分配空间时:迭代器、指针引用都失效。
没有重新分配空间:插入之前都有效,之后的都失效。
deque:
插入首尾之外:都会失效。
插入首位置:迭代器失效,指针引用仍有效。
list 或 forward_list:
一直有效。
容器删除元素(所有被删除的元素的迭代器、指针、引用都会失效):
vector 或 string:
之前的都有效,之后的都失效。
deque:
删除首尾之外:都失效。
删除尾元素:迭代器失效,指针引用有效。
删除首元素:都有效。
list 或 forward_list:
一直有效。
9.4 vector 对象是如何增长的
每次需要分配新内存空间时,将当前容量翻倍。
如果需求小于等于当前容量,reserve什么都不做。
调用shrink_to_fit只是一个请求,标准库并不保证退还内存。
仅在插入或调用resize 或 reserve 时,才有可能重新分配空间。即删除(或全部清除)时,不会改变容量大小。
9.5 额外的string 操作
9.5.1 构造string的其他方法
原来介绍的string:C++ 学习笔记(3)命名空间using、字符串、string、vector、迭代器、数组用const char*构造创建string时,字符串必须以空字符作为结尾,因为拷贝操作在遇到空字符时才会停止。
9.5.2 改变string的其他方法
replace是调用erase和insert的一种简写。9.5.3 string 搜索操作
npos:const_string::size_type类型,初始值-1(无符号型,即最大值)。9.5.5 数值转换
// 找到字符串第一个数值,获取其数字字符串,转换成浮点数。 string s = "pi = 3.14"; float d = stod(s.substr(s.find_first_of("+-.0123456789")));
9.6 容器适配器
适配器(adaptor):标准库的一个通用概念。容器、迭代器和函数都适用。本质上是一种机制,能使某种事物的行为看起来像另外一种事物一样。(就像任天堂给switch加个几块纸板一样。)默认情况下,stack和queue都是基于deque实现的,priority_queue是在vector。
适配器需要有添加和删除能力(要求是顺序容器)。
stack要求拥有back、push_back、pop_back:
vector 、deque 、list。
queue要求拥有back、push_back、front、pop_front:
deque、list。
priority_queue要求拥有front、push_back、pop_back,同时要有随机访问的能力:
vector 、deque。
相关文章推荐
- C++学习笔记19——顺序容器的介绍
- C++学习笔记--顺序容器
- C++学习笔记八-顺序容器(一)
- C++基础的不能再基础的学习笔记——顺序容器(其他操作)
- C++学习笔记20——顺序容器的操作
- C++学习笔记(1) 顺序容器简介
- C++学习笔记(一) 序列式容器及适配器
- C++学习笔记之顺序容器
- C++ 学习笔记 2.1 : 容器和算法(顺序容器、关联容器、泛型算法)
- 笔记:C++学习之旅---顺序容器
- C++学习笔记九-顺序容器(二) - ForFreeDom - 博客园
- C++学习笔记九-顺序容器(二)
- C++学习笔记之容器:顺序容器
- C++学习笔记(六)----关于顺序容器
- C++ Primer学习笔记2--c++顺序容器
- C++学习笔记【第二部分第九章:顺序容器】
- C++ Primer 学习笔记17 容器适配器
- C++ Primer 学习笔记——顺序容器的string操作
- C++基础的不能再基础的学习笔记——顺序容器(基本操作)
- C++学习笔记(2) 顺序容器的使用