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的其他操作以及容器适配器的更多相关文章

  1. C++Primer 第九章

    //1.vector:可变大小数组.支持快速随机访问,在尾部之外的位置插入或删除元素可能很慢.注意点:不要在vector中存放bool类型,vector<bool>并不是一个容器,其实现方 ...

  2. C++ Primer : 第九章 : 顺序容器的定义、迭代器以及赋值与swap

    顺序容器属于C++ STL的一部分,也是非常重要的一部分. 顺序容器包括: std::vector,包含在头文件<vector>中 std::string, 包含在头文件<strin ...

  3. 顺序容器----顺序容器操作,vector对象如何增长,额外的string操作,容器适配器

    一.顺序容器操作 1.向顺序容器添加元素 向顺序容器(array除外)添加元素的操作: 操作 说明 c.push_back(t) 在c的尾部创建一个值为t的元素.返回void c.emplace_ba ...

  4. C++ Primer 第九章 顺序容器

    由于书籍上写的已经很经典了,故大部分用图片的形式来阐述概念,代码纯手打进行验证. 1.顺序容器类型:vector.deque.list.forword_list.array.string. 2.顺序容 ...

  5. C++ Primer : 第九章 : 顺序容器的操作以及迭代器失效问题

    顺序容器的添加.访问.删除操作以及forward_list的特殊操作,还有迭代器失效问题. 一.向容器添加元素 // array不支持这些操作 // forward_list有自己撰于的版本的inse ...

  6. C++ Primer第九章课后编程问题

    1. watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ3V1Z2xlMjAxMA==/font/5a6L5L2T/fontsize/400/fill/I0J ...

  7. 第九章 C99可变长数组VLA详解

    C90及C++的数组对象定义是静态联编的,在编译期就必须给定对象的完整信息.但在程序设计过程中,我们常常遇到需要根据上下文环境来定义数组的情况,在运行期才能确知数组的长度.对于这种情况,C90及C++ ...

  8. 【C++】《C++ Primer 》第九章

    第九章 顺序容器 一.顺序容器概述 顺序容器(sequential container):为程序员提供了控制元素存储和访问顺序的能力.这种顺序不依赖于元素的值,而是与元素加入容器时的位置相对应. 不同 ...

  9. C++ Primer Plus学习:第九章

    C++第九章:内存模型与名称空间 C++在内存中存储数据方面提供了多种选择.可直接选择保留在内存中的时间长度(存储持续性)以及程序哪一部分可以访问数据(作用域和链接)等. 单独编译 程序分为三个部分: ...

随机推荐

  1. daemon

    关于daemon,其最简单的用法是: , ) == -) ; 将上面代码放置程序中,程序执行到这一行,就会自动进入后台运行,不再与终端交互,即终端再输入的参数无效,程序的输出(比如printf等)无效 ...

  2. 一模 (6) day2

    第一题: 题目大意:求最长公共上升子序列(LICS): 解题过程: 1.一开始想到模仿求最长公共子序列的方法,F[i][j]表示A串前i个,B串前j个的最长公共子序列,很明显当A[i]!= B[j]时 ...

  3. VS2010连接SQLite数据库

    Visual studio 2010及以上版本,连接SQLite数据库 1.在Sqlite开发站点下载SQLite的.exe安装包 Ctrl+F搜索这条语句:This is the only setu ...

  4. zatree第三方插件

    Zabbix安装第三方插件zatree2.4.5 1.下载zatree第三方插件https://github.com/spide4k/zatree.git 2.检查PHP环境需要支持php-xml.p ...

  5. 微软TechEd2013大会门票热卖!

    微软TechEd2013大会将在北京.上海两地隆重举行! 会议时间安排如下: 北京:12月5日—6日  国家会议中心 上海:12月11日—12日  国际会议中心 现在是门票热卖时期,票价:2688.0 ...

  6. 04-树5 Complete Binary Search Tree

    这题也是第二次做,本想第一次做时参考的算法会和老师讲的一样,不想老师讲的算法用在这题感觉还不如思雪园友的算法(http://www.cnblogs.com/sixue/archive/2015/04. ...

  7. 2016 - 1 -17 GCD学习总结

    一:GCD中的两个核心概念,队列与任务: 1.任务:执行什么操作.(代码块 block) 任务执行的类型分为以下两种: 1.1同步执行任务:在当前线程执行任务.不会开辟新的线程. 1.2异步执行任务: ...

  8. golang函数调用计时

    package main import ( "log" "time" ) func f() { defer timeoutCheck("f slow& ...

  9. windows-ubuntu环境变量的设置格式的不同

    1  在Ubuntu下输出环境变量,比如JAVA_HOME, 使用cat或者echo $JAVA_HOME即可,但是在windows下不可以, windows不支持cat命令,只能使用echo %JA ...

  10. 中文Ubuntu系统根目录文件夹名称变为英文

    Ubuntu中文安装后,家目录均为中文,如“下载” “文档”等等,在使用Shell时很不方便,可用如下方法将这些文件夹名称改回英文 1.使用命令 export LANG=en_US xdg-user- ...