C++ Primer : 第九章 : vector变长、string的其他操作以及容器适配器
vector变长机制、string的其他构造方法,添加、替换和搜索操作,string比较和数值转换,最后是容器适配器。
vector对象是如何增长的
vector和string类型提供了一些成员函数,允许我们与它实现中内存分配的部分互动:capacity()操作告诉我们容器在不扩张内存空间的情况下可以容纳多少个元素,reserve()操作允许我们通知容器它应该准备保存多少个元素。
// shrink_to_fit只适用于vector、string和deque
// capacity和reserve只适用于vector和string
c.shrink_to_fit; 请将capacity()减少为size()相同大小
c.capacity(); 不重新分配内存空间的话,c可以保存多少元素
c.reserve(n); 分配至少能容纳n个元素的内存空间
// reserve并不改变容器中元素的数量,它仅影响vector预先分配多大的内存空间
只有当需要的内存空间超过当前容量时,reserve调用才会改变vector的容量。如果需要大小大于当前容量,reserve至少分配与需求一样大的内存空间。(一般是2倍)
如果需求大小小于或等于当前容量,reserve什么也不做,特别是,当需求大小小于当前容量时,容器并不会退回内存空间。因此在调用reserve之后,capacity()将会大于或等于传递给reserve的参数!
在新的标准里,我们可以通过shrink_to_fit来要求deque、vector或string退回不需要的内存空间,此函数指出我们不再需要多余的内存空间,但是实际上,会忽略此请求,调用shrink_to_fit并不保证一定会退回内存空间。
capacity和size
capacity指在不重新分配内存空间的情况下,容器最多可以保存多少个元素,而size指的是当前容器已经保存的元素数量。
vector<int> ivec;
// size应该为0,而capacity依赖具体实现
cout << "ivec : size : " << ivec.size()
<< "capacity : " << ivec.capacity() << endl;
// 添加24个元素
for(vector<int>::size_type i = 0; i < 24; ++i)
ivec.push_back(i);
// capacity应该大于等于24,依赖具体实现
cout << "ivec : size : " << ivec.size()
<< "capacity : " << ivec.capacity() << endl;
// 我们可以预先分配一些资源:
ivec.reserve(50);
cout << "ivec : size : " << ivec.size()
<< "capacity : " << ivec.capacity() << endl;
这样,capacity就和reserve的参数一样大了:
我们可以将空余的26个位置填满:
while(ivec.size() != ivec.capacity())
ivec.push_back(0);
cout << "ivec : size : " << ivec.size()
<< "capacity : " << ivec.capacity() << endl;
这证明,我们没有重新分配内存空间,就不会调用reserve,capacity也就不变。
继续添加一个元素后,超出了预留空间,vector就要重新分配内存空间了:
ivec.push_back(0);
std::cout << "ivec : size : " << ivec.size ()
<< " capacity : " << ivec.capacity () << std::endl;
输出:ivec : size : 51 capacity : 75
我们可以用shrink_to_fit来要求退回不需要的内存空间:
ivec.shrink_to_fit();
std::cout << "ivec : size : " << ivec.size ()
<< " capacity : " << ivec.capacity () << std::endl;
输出: ivec : size : 51 capacity : 51
shrink_to_fit依赖于具体的实现,有些机器可能不会理会此操作!
额外的string操作
构造string的其他方法:
// n、len2和pos2都是无符号值
string s(cp, n); s是cp指向的数组中前n个字符的拷贝,数组至少包含n个元素
string s(cp, pos2); s是string s2从下标pos2开始的字符的拷贝,若pos2>s2.size(),该行为未定义
string s(cp, pos2, len2); s是string s2从下标pos2开始的len2个字符的拷贝,若pos2>s2.size(),该行为未定义,不管len2多大,最多拷贝s2.size() - pos2个字符
特别的是,当我们从一个const char*创建string时,指针指向的数组必须以空字符'\0'结尾,拷贝操作遇到空字符停止。当从一个string拷贝字符时,如果位置大于size,则构造函数抛出一个out_of_range异常
substr操作:返回一个string,它是原始string的一部分或全部拷贝。
s.substr(pos, n); 返回一个string,包含s从pos开始的n个字符的拷贝,pos默认为0,n默认为s.size() - pos
改变string的其他方法:
除了接受迭代器的insert和erase版本外,string还提供了下标的版本:
s.insert(s.size(), 5, '!'); // 在s的末尾插入5个'!'
s.erase(s.size() - 5, 5); // 删除s的最后5个字符
还有接受C风格字符数组的insert和assign版本:
const char* cp = "Stately, plump Buck";
s.assign(cp, 7); // s == "Stately"
s.insert(s.size(), cp + 7); // s == Stately, plump Buck
也可以指定将来自其他string或子字符串插入到当前的string中:
string s = "some string", s2 = "some other string";
s.insert(0, s2); // 在s开始的位置之前插入s2的拷贝
s.insert(0, s2, 0, s2.size()); // 在s开始的位置插入从s2[0]开始的s2.size()个字符
append和replace函数:
string定义了额外的这两个函数来改变string:
string s("C++ Primer"); s2 = s;
s.insert(s.size(), " 4th Ed."); // s == "C++ Primer 4th Ed."
s2.append(" 4th Ed."); // 等价方法,将" 4th Ed."追加到s2的末尾
replace是调用erase和insert的一种简写形式:
s.erase(11, 3); // s == "C++ Primer Ed."
s.insert(11, "5th"); // s == "C++ Primer 5th Ed."
// 等价方法,s2 == "C++ Primer 5th Ed."
s2.replace(11, 3, "5th");
replace插入的文本不一定要和替换的文本一样长。
s2.replace(11, 3, "Fifth"); // s2 == "C++ Primer Fifth Ed."
string的assign和append函数,assign函数总是替换string中的内容,append总是添加到末尾,replace有两个版本,除了下标,还有接受迭代器的版本。
string的搜索操作:
string提供了6中不同的搜索函数,每个函数都返回一个string::size_type值,表示匹配的下标,如果没有找到,返回一个名为string::npos的static成员,它是const string::size_type类型,并初始化为-1,由于npos是usigned类型,意味着npos等于任何string最大的可能大小。
s.find(args); 查找s中args第一次出现的位置
s.rfind(args); 查找s中args最后一次出现的位置
s.find_first_of(args); 在s中查找args中任何一个字符第一次出现的位置
s.find_last_of(args); 在s中查找args中任何一个字符最后一次出现的位置
s.find_first_not_of(args); 在s中查找第一个不在args中的字符
s.find_last_not_of(args); 在s中查找最后一个不在args中的字符
我们可以给这些操作传递一个可选的开始位置,默认情况下,这个位置被置为0;
string::size_type pos = 0;
while((pos = name.find_first_of(numbers, 0)) != string::npos)
cout << "found number at index " << pos
<< " element is " << name[pos++] << endl;
string的数值转换:
to_string(val); 返回数值val的string表示,val可以是任何算数类型。对每个浮点类型和int或更大的整形,都有相应版本的to_string,与往常一样,小整形会被提升。
stoi(s,p,b); 返回s的起始子串的数值,类型分别是int、long、unsigned long、long long、unsigned long long。
stol(s,p,b); b表示转换的基数,默认是10,p是size_t指针,用来保存s中第一个非数值字符的下标,p默认为0,即 函数不保存下标。
stoul(s,p,b);
stoll(s,p,b);
stoull(s,p,b);
stof(s,p); 返回s的起始子串的数值,返回值分别是float、double和long double
stod(s,p);
stold(s,p);
如果string不能转换为一个数值,这些函数会抛出一个invalid_argument异常,如果转换得到的数值无法用于任何类型来表示,则抛出一个out_of_range异常。
容器适配器:
标准库定义了三个容器适配器: stack、queue和priority_queue。
所有容器适配器都支持的操作和类型:
size_type 一种类型,足以保存当前类型的最大对象的大小
valua_type 元素类型
container_type 实现适配器的底层容器类型
// 所有容器都支持的关系运算符:
== != < <= > >=
a.empty(); 判断a是否为空
a.size(); 返回a的大小
swap(a,b); 交换a和b的元素
a.swap(b); a和b的类型必须相同,而且它们底层的容器类型也必须相同
默认情况下,stack和queue是基于deque实现的,priority_queue是在vector上实现的。我们可以在创建一个适配器时将一个命名的顺序容器做为第二个类型参数,来重载默认容器类型:
stack<string, vector<string>> stk;
所有适配器都要求具有添加和删除元素的能力,所以底层容器不能是array,类似的,也不能用forward_list来构造适配器。
除过array和forward_list之外的任何顺序容器类型都可以构造stack
queue要求back、push_back、front和push_front,因此queue可以构造在list或deque之上,但不能基于vector。
priority_queue除了front、push_back和pop_back操作之外还要求随机访问能力,因此它可以构造于vector和deque之上,但不能基于list
一些栈操作:
// 栈默认deque实现,也可以构造于list或vector
s.pop(); 删除栈顶元素,但不返回该元素值
s.push(item); 拷贝item元素到栈顶
s.emplace(args); 由args构造一个元素添加到栈顶
s.top(); 返回栈顶元素,但不弹出
虽然stack默认deque实现,但不能再一个stack上使用deque的操作!
队列操作:
// queue默认基于deque实现,priority_queue默认基于vector实现
q.pop(); 删除队首元素,但不返回它
q.front(); 返回首元素,但不删除它
q.back(); 返回尾元素,但不删除它
q.top(); 返回最高优先级的元素,但不删除它,只适用于priority_queue
q.push(item); 拷贝item到queue末尾或priority_queue中恰当的位置
q.emplace(args); 由args构造
priority_queue允许我们为队列中的元素建立优先级,新加入的元素会排在所有优先级比它低的已有的元素之前。默认情况下,标准库在元素类型上使用 < 来确定相对优先级。
C++ Primer : 第九章 : vector变长、string的其他操作以及容器适配器的更多相关文章
- C++Primer 第九章
//1.vector:可变大小数组.支持快速随机访问,在尾部之外的位置插入或删除元素可能很慢.注意点:不要在vector中存放bool类型,vector<bool>并不是一个容器,其实现方 ...
- C++ Primer : 第九章 : 顺序容器的定义、迭代器以及赋值与swap
顺序容器属于C++ STL的一部分,也是非常重要的一部分. 顺序容器包括: std::vector,包含在头文件<vector>中 std::string, 包含在头文件<strin ...
- 顺序容器----顺序容器操作,vector对象如何增长,额外的string操作,容器适配器
一.顺序容器操作 1.向顺序容器添加元素 向顺序容器(array除外)添加元素的操作: 操作 说明 c.push_back(t) 在c的尾部创建一个值为t的元素.返回void c.emplace_ba ...
- C++ Primer 第九章 顺序容器
由于书籍上写的已经很经典了,故大部分用图片的形式来阐述概念,代码纯手打进行验证. 1.顺序容器类型:vector.deque.list.forword_list.array.string. 2.顺序容 ...
- C++ Primer : 第九章 : 顺序容器的操作以及迭代器失效问题
顺序容器的添加.访问.删除操作以及forward_list的特殊操作,还有迭代器失效问题. 一.向容器添加元素 // array不支持这些操作 // forward_list有自己撰于的版本的inse ...
- C++ Primer第九章课后编程问题
1. watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ3V1Z2xlMjAxMA==/font/5a6L5L2T/fontsize/400/fill/I0J ...
- 第九章 C99可变长数组VLA详解
C90及C++的数组对象定义是静态联编的,在编译期就必须给定对象的完整信息.但在程序设计过程中,我们常常遇到需要根据上下文环境来定义数组的情况,在运行期才能确知数组的长度.对于这种情况,C90及C++ ...
- 【C++】《C++ Primer 》第九章
第九章 顺序容器 一.顺序容器概述 顺序容器(sequential container):为程序员提供了控制元素存储和访问顺序的能力.这种顺序不依赖于元素的值,而是与元素加入容器时的位置相对应. 不同 ...
- C++ Primer Plus学习:第九章
C++第九章:内存模型与名称空间 C++在内存中存储数据方面提供了多种选择.可直接选择保留在内存中的时间长度(存储持续性)以及程序哪一部分可以访问数据(作用域和链接)等. 单独编译 程序分为三个部分: ...
随机推荐
- CodeForces 86D(Yandex.Algorithm 2011 Round 2)
思路:莫队算法,离线操作,将所有询问的左端点进行分块(分成sqrt(n) 块每块sqrt(n)个),用左端点的块号进行排序小的在前,块号相等的,右端点小的在前面. 这样要是两个相邻的查询在同一块内左端 ...
- 常州培训 day6 解题报告
第一题: 题目大意: 给出一个N*N的矩阵,矩阵元素均为0或1.定义矩阵权值为sum(F[i][j]*F[j][i]); 给出K个操作: 询问矩阵的权值mod 2. 将矩阵的某一行元素取反(0变成1, ...
- 戴文的Linux内核专题:04安全
转自Linux中国 Linux内核是所有Linux系统的核心.如果有任何恶意代码控制或破害了内核的任何一部分,那么系统会严重受损,文件可能被删除或损坏,私人信息可能被盗等等.很明显,保持内核安全涉及到 ...
- iOS程序的启动过程-UIWindow
UIApplicationMain main函数中执行了一个UIApplicationMain这个函数 int UIApplicationMain(int argc, char *argv[], NS ...
- Linux下screen命令
//1.列出当前的screenscreen -ls //2.新建一个screen,直接在命令行键入screen命令 screen -S [会话名称][root@www.lnuxidc.com ~]# ...
- PDF2SWF转换只有一页的PDF文档,在FlexPaper不显示解决方法
问题:PDF2SWF转换只有一页的PDF文档,在FlexPaper不显示! FlexPaper 与 PDF2SWF 结合是解决在线阅读PDF格式文件的问题的,多页的PDF文件转换可以正常显示,只有一页 ...
- java获取获得Timestamp类型的当前系统时间。
java获取获得Timestamp类型的当前系统时间. java获取取得Timestamp类型的当前系统时间 格式:2010-11-04 16:19:42 方法1: Timestamp d = n ...
- RESTful Web Services测试工具推荐
命令行控的最爱:cURL cURL是一个很强大的支持各种协议的文件传输工具,用它来进行RESTful Web Services的测试简直是小菜一碟.这个工具基本上类Unix操作系统(各种Linux.M ...
- ubuntu知识收集
1 就像windows下的环境变量分为系统变量和用户变量一样,ubuntu下也是一样,四种环境变量, 1 系统环境变量:/etc/enviroment, 是整个系统的环境变量,与登录用户无关,在这 ...
- HackRF实现无线门铃信号分析重放
文章特点:数据解码方面实在是没什么信心,存在分析错乱的可能性,所幸发出来共同探讨,恳请鞭策. 0x01 概述 这是一款工作在315Mhz频段的无线遥控门铃,根据查阅官方手册以及芯片信息,确定其采用了e ...