string::reserve和string::size疑点分析

对于C++的vector容器模板类,存在size和capacity这样两个概念,可以分别通过vector的size()和capacity()方法获得该vector当前的size和capacity值。相应的,vector提供了两个方法来分别对size和capacity进行操作,它们就是resize方法和reserve方法。

首先,对于size和capacity,这是两个比较容易混淆的概念。都说要抱着问题来学习,才能做到事半功倍。那么,这里便提出三个问题:什么是vector的大小(即size)?什么是vector的容量(即capacity)?这两个概念的区别在哪里?

对于抽象的问题,只要我们把它们同我们的生活实际相结合,将问题具象化,自然就会很好的理解。

就拿我们的办公室举例,假设,我们部门的办公地点位于公司大楼的六楼。在我们的办公室里面,放置了100套办公桌椅(工位),公司说按照一个萝卜一个坑来算,你们部门最多只能招这么多人,那么,这时我们可以说,我们部门的容量(即capacity)就是100人,如果我们部门是公司刚成立的部门,正处于发展壮大的阶段,目前只有40为员工,也就是说,办公室里只坐了40个人,另外60个工位是空着的,那么,我们可以说,我们部门当前的大小(即size)是40人。这实际上就是size和capacity的区别。类比到vector,size和capacity的概念自然就很清楚了。

cplusplus.com中对capacity是这样定义的:

This capacity is not necessarily equal to the vector size. It can be equal or greater, with the extra space allowing to accommodate for growth without the need to reallocate on each insertion.

一个allowing道出了真谛!这里还要区分两个概念,就是:为vector分配的存储空间和vector的大小是两个不同的概念。为vector分配的存储空间,实际上就是capacity,指的是当前vector最多能使用的存储空间,是大于等于vector的大小的,当vector实际需要使用的存储空间大于当前分配给它的存储空间时,需要重新为其分配存储空间。

cplusplus.com中对size的定义是:

This is the number of actual objects held in the vector, which is not necessarily equal to its storage capacity.

实际上就是vector中当前实际存储的元素个数。

弄清楚了size和capacity这两个概念之后,对于resize和reserve两个方法就很好理解了。

cplusplus.com中对reserve的定义是:

Request a change in capacity

Requests that the vector capacity be at least enough to contain n elements.

If n is greater than the current vector capacity, the function causes the container to reallocate its storage increasing itscapacity to n (or greater).

In all other cases, the function call does not cause a reallocation and the vector capacity is not affected.

This function has no effect on the vector size and cannot alter its elements.

从上面的说明中,可以得到以下信息:

1、reserve方法被用来重新分配vector的容量大小;

2、只有当所申请的容量大小n大于vector的当前容量时,才会重新为vector分配存储空间;

3、reserve方法对于vector的大小(即size)没有任何影响;

具体通过下面的例子验证

#include <iostream>

#include <vector>


using namespace std;


int main()

{

vector<int> vect;


vect.reserve(5); // 调用reserve方法为vect分配容量(即存储空间)


vect.push_back(1);

vect.push_back(2);

vect.push_back(3);

vect.push_back(4); // 插入4个元素


cout << vect.size() << endl; // vect的实际大小(即包含多少元素)

cout << vect.capacity() << endl; // vect的容量大小


return 0;

}


结果为

从结果中,就可以很清楚的看到capacity和size的区别。

下面看一个综合的例子,可以从中获得很多信息:

#include <iostream>

#include <vector>


using namespace std;


int main()

{

vector<int> vect;


vect.reserve(5);


vect.push_back(1);

vect.push_back(2);

vect.push_back(3);

vect.push_back(4);


cout << vect.size() << endl;

cout << vect.capacity() << endl;


vect.push_back(5);

vect.push_back(6); // 插入两个元素,此时vect的大小大于之前分配的容量5


cout << "size1 = " << vect.size() << endl;

cout << "capacity1 = " << vect.capacity() << endl;


vect.push_back(7);

vect.push_back(8); // 在插入两个元素,和上面的结果进行对比,会有意外收获

cout << "size1_1 = " << vect.size() << endl;

cout << "capacity1_1 = " << vect.capacity() << endl;


vect.reserve(3); // 当程序执行到此处时,vect的容量大小一定是大于3的


cout << "size2 = " << vect.size() << endl;

cout << "capacity2 = " << vect.capacity() << endl;


vect.reserve(12);


cout << "size3 = " << vect.size() << endl;

cout << "capacity3 = " << vect.capacity() << endl;


return 0;

}
执行结果为:

对这一执行结果,一点点进行分析:

1、首先,看结果size1和capacity1,在打印这两个结果前,程序向vect中插入了两个元素,之前,vect中存在4个元素且容量为5,按照我之前的设想,如果我采用push_back向vect中插入元素时,当元素数量大小capacity时,vect的capacity会随着size变大而变大,但应该是和size相等。但此处,vect的大小为6,但是容量却是7,且这个7,来的很是突然,我往哪个方面靠都靠不上啊。好吧,先把这个疑问姑且放下,现在我们猜想,是不是push_back中针对这种情况会有处理,始终保持vect的capacity比size至少大1,带着这个猜想继续向下看,我又向vect中插入了两个元素,此时,vect的大小为8,若是我们刚才的猜想是正确的话,则此时,vect的capacity应该增大为9了,但是此时结果size1_1和capacity1_1却给了我当头一棒,这个10又是怎么回事?学习编程永远记住一件事情,所有问题的答案,都能从代码中找到。于是,我顺着vector的push_back源码开始找下去,就有了下面这段追踪代码

void push_back(_Ty&& _Val)

...

if (this->_Mylast == this->_Myend)

_Reserve(1);

...


void _Reserve(size_type _Count)

{ // ensure room for _Count new elements, grow exponentially

size_type _Size = size();

if (max_size() - _Count < _Size)

_Xlen();

else if ((_Size += _Count) <= capacity())

;

else

reserve(_Grow_to(_Size));

}


size_type _Grow_to(size_type _Count) const

{ // grow by 50% or at least to _Count

size_type _Capacity = capacity();


_Capacity = max_size() - _Capacity / 2 < _Capacity

? 0 : _Capacity + _Capacity / 2; // try to grow by 50%

if (_Capacity < _Count)

_Capacity = _Count;

return (_Capacity);

}

由这段官方实现代码,终于找到了答案,原来在使用push_back向vect中插入元素时,如果当前元素数量大于vector的capacity时,会重新为vector分配存储空间,而分配的原则就是:

                    原capacity + 原capacity / 2

这样,就解释了上面的7和10两个结果,最初,vect的容量大小为5,在第一次插入两个元素后,vector中的元素数量大于5了,所以此时,会重新为vect分配容量,分配大小为5 + 5 / 2 = 7,而同样的,第二次重新分配vect的容量是7 + 7 / 2 = 10,这就合理的解决了刚才的疑问。

2、当vect的容量大小为10时,再调用reserve方法,重新为其设置容量为3时,不会进行任何操作,可以看到,vect的容量大小还是10;

3、当为vect设置容量大小为12时,可以看到,成功的改变了vect的容量大小;

4、不论哪次调用reserve方法,vect的size大小在调用前后,始终没有被改变过。

到此,是我对reserve方法的一些思考和验证。

原文转载自:https://blog.csdn.net/vampirem_chosen_one/article/details/50519870

猜你喜欢

转载自blog.csdn.net/Linux_bin/article/details/81740741