140-C++vector的rever()和resize()函数
⼀、基本概念
rever()和resize()是⽤来给容器vector、list和string预留空间或调整他们的⼤⼩:rerve()⽤来保留(扩充)容量,他并不改变容器的有限元素个数;resize()则调整容器⼤⼩(size,有效元素的个数),⽽且有时候会增⼤容器的容量
⾸先我们得搞清楚“容量”和“容器”以及“有效元素”的概念
容量是为了减少那些使⽤连续空间(线性空间)存储元素的容器在增加元素时重新分配内存空间的次数的⼀种机制,即当增加元素且剩余空间内存不⾜时,按照⼀定⽐例(通常是原来容量的1.5或2倍)多分配⼀些空闲空间已备将来再增加元素时使⽤,以提⾼插⼊操作的性能。⼀个具有多余容量的std::vector得典型内存映像如图⼀所⽰
图中迭代器start和finish之间的元素就是容器的有效元素(实际上是有效元素对象本⾝的内存单元),⽽strart和end_of_storage之间的空间就是该容器的总容量。finish和end_of_storage之间的空闲就是冗余容量,冗余容量不属于容器
多余出来的容量(空闲存储空间)是未经初始化的(并不是调⽤元素类型的默认构造函数来初始化)。我们可以从std::vector的size()和capacity()这两个成员函数的实现上看出容器所管辖元素空间和容量的区别:
size_type capacity() const {return (start==0?0:end_of_storage);}
size_type size() const {return (start==0?0:finish);}幼儿园一日生活流程
⼀个容器可以没有任何有效元素,但是却有许多冗余的容量;或者⼀个容器可以没有任何冗余的容量,全是有效元素;或者既有⼀些有效元素⼜有⼀些冗余容量
⼆、⽤途
悉尼奥运会下⾯我们来看看rerve()和resize()到底做了什么
rerve()原型如下:
void rerve(size_type n);‘
其中n就是⽤户请求保留的总容量的⼤⼩(在不重新分配内存的情况下可容纳元素的个数)。rerve()可按如下情况实现:
(1)如果n⼤于容器现有的容量(即capacity()),则需要在⾃由内存区为整个容器重现分配⼀块新的更⼤的连续空间,其⼤⼩为
n*sizeof(T),然后将容器内所有的有效元素从旧位置全部复制到新位置(调⽤拷贝构造函数),最后释放旧位置的所有存储空间并调整容器对象的元素位置指⽰器(即让那3个指针指向新内存区的相应位置)。也就是说,如果请求容量⽐原有容量⼤的话,结果是容器的冗余容量加⼤(即end_of_starage指针所指的相对位置发⽣了变化),⽽容器本⾝的有限元素不会发⽣任何变化
(2)否则什么都不做。如图⼆所⽰。
慈怎么组词resize()顾名思义,他调整容器的⼤⼩(size),有时也会扩⼤容器的容量,话句话说,不管容器当前包含多少个有效元素,也不管容器的冗余容量是多少,他都将容器的有效元素调整为⽤户指定的个数。resize()原型如下:
void resize(size_type n,const T& c=T());
其中n就是最后要保持的元素个数,如果需要新增元素的话,c则是新增元素的默认初始值。下⾯是resize()的实现策略:
(1)如果n⼤于容器当前的⼤⼩(即size()),则在容器的末尾插⼊(追加)n-size()个初始值为c的元素,如果不指定初始值,则⽤元素类型的默认构造函数来初始化每⼀个新元素(可能会引起内存重分配以及容器容量的扩张)
(2)若果n⼩于容器当前的⼤⼩,则从容器末尾删除size()-n个元素,但不释放元素本⾝的空间,因此容量不变。
(3)否则什么也不做。
3、注意事项
我们可以将容器看做⼀个区间,我们知道,出了调⽤容器的某些⽅法可以改变容器的⼤⼩,在容器外部没有任何⽅法可以做到这⼀点。因此如果想使⽤迭代器在冗余量的空间上通过赋值来给容量增加元素的话,结果会⼤失所望。我们来举个栗⼦:
std::list<int> i1;
std::vector<int> v1;
打扫的英语怎么读for(int c=0;c<10;c++)
i1.push_back(c);
std::copy(i1.d,v1.begin);//拷贝赋值
std::copy(v1.d,ostream_iterator<int>(std::cerr,"\t"));
这段程序显然是错误的,虽然v1.rerve()为vector预留了空间,但是改变的只是容器的容量。同时在copy()算法中对容器元素复制也不会改变容器的⼤⼩(毕竟算法不直到容器的存在,他只知道区间),
因此复制后容器的size()仍然为0,虽然list的元素已经被复制到了为vector预留的空间上,结果可想⽽知;没有输出任何东西,!vector在复制前后的状态变化可以⽤图三来说明
因此rerve()不能与赋值运算符配合,⽐如不应该与简单的copy()算法合作,⽽应该与push_back()、inrt()等操作合作,或者与使⽤inrt(迭代器的copy()算法合作。例如:
饭店怎么经营才能吸引客人
std::copy(i1.begin(),i1.end,std::back_inrter(v1));仙人掌的外貌
这样的话,copy()算法通过inrt迭代器不仅给容器增加了元素,⽽且也间接的改变了容器的⼤⼩。
然⽽,resize()与赋值运算符及inrt()、push_back()等都可以合作,例如上⾯的例⼦可以按如下编写:关于感恩的画
std::list<int> i1;
std::vector<int> v1;
for(int c=0;c<10;c++)
i1.push_back(c);
伍佰最好听的十首歌
std::copy(i1.d,v1.begin);//拷贝赋值
std::copy(v1.d,ostream_iterator<int>(std::cerr,"\t"));
这次,就可以输出正确的结果了,如图四所⽰
相反的,使⽤resize()缩减容器⼤⼩也是类似的