9.4 vector对象是如何增长的

为了支持快速随机访问,vector将元素连续储存。为了避免每次添加新元素都要重新分配存储空间,vector和string的实现通常会分配比新的空间需求更大的内存空间。容器预留这些空间作为备用,可以保存更多的新元素。使用此策略后,扩张操作通常比list和deque要快。

  • 管理容量的成员函数
------- 容器大小管理操作
c.shrink_to_fit() 请将capacity减少为与size大小相同
c.capacity() 不重新分配内存空间的话,c可以保存多少元素
c.reserve(n) 分配至少能容纳n个元素的储存空间

shrink_to_fit只适用于vector、string和deque。

capacity和reserve只适用于vector和string。

只有当需要的内存空间超过超过当前容量时,reserve调用才会改变vector的容量。如果需求大小大于当前容量,reserve至少分配与需求一样大的内存空间(可能更大)。如果需求大小小于或等于当前容量,reserve什么也不做。特别是,当需求大小小于当前容量时,容器不会退回内存空间。

类似的,resize成员函数只改变容器中元素的数目,不是容器的容量,同样不能使用resize来减少容器预留的储存空间。

在新标准库中,可以调用shrink_to_fit来要求deque、vector或string退回不需要的内存空间。但是具体的实现可以选择忽略此请求,调用shrink_to_fit也不保证一定退回内存空间。

  • capacity和size
vector<int> ivec;
cout<< " ivec: size: " << ivec.size() << " capacity: " << ivec.capacity() <<endl;
for(vector<int>::size_type ix = 0; ix != 24; ++ix)
{
  ivec.push_back(ix);
}
cout<< " ivec: size: " << ivec.size() << " capacity: " << ivec.capacity() <<endl;
vector<int> ivec;
ivec.reserve(50);
cout<< " ivec: size: " << ivec.size() << " capacity: " << ivec.capacity() <<endl;
while(ivec.size() != ivec.capacity())
{
  ivec.push_back(0);
}
cout<< " ivec: size: " << ivec.size() << " capacity: " << ivec.capacity() <<endl;

只要没有操作需求超出vector的容量,就不能重新分配内存空间。

shrink_to_fit只是一个请求,标准库不保证退还内存。

9.5 额外的string操作

9.5.1 构造string的其他方法

--------- 构造string的其他方法
string s(cp,n) s是cp指向的数组中前n个字符的拷贝,此数组至少应该包含n个字符
string s(s2,pos2) s是string s2从下标pos2开始的字符的拷贝,若pos2>s2.size(),构造函数的行为未定义
string s(s2,pos2,len2) s是string s2从下标pos2开始len2个字符的拷贝。若pos2>s2.size(),构造函数的行为未定义。不管len2是多少,构造函数至多拷贝s2.size()-pos2个字符
const char* cp = "Hello World!!!";
char noNull[] = {'H', 'W'};
string s1(cp);
string s2(noNull,2);
string s3(noNull); //未定义:noNULL不是以空字符结束
string s4(cp+6,5);
string s5(s1,6,5);
string s6(s1,6);
string s7(s1,6,20); //只拷贝到末尾
string s8(s1,16); //抛出out_of_range异常
  • substr操作 substr操作返回一个string,它是原始string的一部分或全部的拷贝。可以传递给substr一个可选的开始位置和计数值。
string s("Hello World");
string s2 = s.substr(0,5);
string s3 = s.substr(6);
string s4 = s.substr(6,11);
string s5 = s.substr(12); //抛出一个out_of_range异常

9.5.2 改变string的其他方法

除了接受迭代器的insert和erase版本外,string还提供了接受下标的版本。

s.insert(s.size(), 5, '!'); //在s末尾插入5个!
s.erase(s.size() - 5, 5); //在s删除最后5个字符

标准库string还提供了C风格字符数组的insert和assign版本。

const char *cp = "Stately, plump Buck";
s.assign(cp, 7);
s.insert(s.size(), cp+7);

还可以指定其他string或子字符串的字符插入到当前string中或赋予当前string。

string s = "some string", s2 = "some other string";
s.insert(0, s2); //在s中位置为0之前插入s2拷贝
s.insert(0, s2, 0, s2.size()); //在s[0]之前插入s2
  • append和replace函数
string s("C++ Primer"), s2 = s;
s.insert(s.size(), "4th Ed.");
s2.append("4th Ed"); //与上一句等价
s2.erase(11, 3); //删除三个元素
s2.insert(11, "5th"); //插入“5th”
s2.replace(11, 3, "5th"); //与上两句等价

调用replace时,插入的文本不需要和被替换的文本一样长。

  • 改变string的多种重载函数
----------- 修改string的操作
s.insert(pos,args) 在pos之前插入args指定的字符。pos可以是下标或迭代器。接受下标的版本返回一个指向s的引用,接受迭代器的版本返回指向第一个插入字符的迭代器
s.erase(pos,len) 删除从pos位置开始的len个字符。如果len被省略,则删除从pos开始直至s末尾的所有字符,返回一个指向s的引用
s.assign(args) 将s中的字符替换为args指定的字符。返回一个指向s的引用
s.append(args) 将args追加到s。返回一个指向s的引用
s.replace(range,arge) 删除s范围range中的字符,替换为args指定的字符,range或者是一个下标一个长度,或是一对指向s的迭代器。返回一个指向s的引用
replace replace insert insert args可以是
str
str,pos,len
cp,len
cp
n,c
b2,e2
初始化列表

9.5.3 string搜索操作

----- 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中的元素
args必须是以下形式之一
c,pos 从s中位置pos开始查找字符c。pos默认为0
s2,pos 从s中位置pos开始查找字符串s2.pos默认为0
cp,pos 从s中位置pos开始查找指针cp指向的以空字符结尾的C风格字符串。pos默认为0
cp,pos,n 从s中位置pos开始查找指针cp指向的数组前n个字符。pos和n无默认值。

搜索操作返回指定字符出现的下标,是string::size_type类型,如果未找到返回nops,类型为const string::size_type类型,初始化值为-1。

string name("AnnaBelle");
auto pos1 = name.find("Anna"); //pos == 0
string lowercase("annabelle");
auto pos2 = lowercase.find("Anna"); //pos2 == nops
  • 指定在哪里开始搜索
string::size_type pos = 0;
//循环查找name中下一个数
while((pos = name.find_first_of(numbers, pos)) != string::nops)
{
  cout<<"found number at index: " << pos<< "element is " << name[pos] << endl;
  ++pos;
}
  • 逆向搜索