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;
}
- 逆向搜索