vector的size和capacity有什么区别?怎么使capacity值为0?

1 篇文章 0 订阅

要说清这个问题,先抛出另外一个问题:vector和普通的数组有什么区别?

你可能会说:大家都知道,vector是动态数组~~

没错!  但是怎么个动态法?怎么实现的?

好,先说一下普通数组,比如:int arr[10]或者int *arr = new int[10]; 其实是你到内存里占了10个int大小的地方(空间)

当然,你可以这样操作:int a = arr[100];   arr[100] = 10;  这样编译器并不会报错,最多会警告你----你有越界行为。

       也就是说,你一开始说好了,你只占10个大小的地方,后来你出尔反尔,又去访问或者操作第100个地方(为了说明问题,事实上是第101个),那么内存的“管理员”他没有不让你操作的权利,只是给你出示了“黄牌警告”,告诉你:你去操作吧,出了问题概不负责!!!
       这就是数组越界问题,越界会造成未知的问题(程序崩溃等等),即你写的程序不受你控制了,或者不是你想要的结果(比如:你越界访问的地方是别人的地方,如果别人也没做“防护”,那么你修改了那个地方的值,就会让别人的会出现未知错误)。为了避免这个问题,那就老老实实的在那个10个大小的地方活动。

但是,在实际应用中,程序员的确有这样的需求:我开始是分配了10个大小的地方,但是我想给它后面添加一个或者给中间某个位置插入一个,变成连续11个数值。

      我再描述一下这个需求:在一个连续的数组添加元素,还能保证新的数组仍然在内存连续,也就是说用下标可以访问(arr[10]访问第11个元素)。

 vector就实现了这样的功能,当然vector功能不止这一个,还有很多操作(push_back,insert等)。

那么,vector是怎么实现这样的功能的?可以参考《STL源码剖析》

我们以push_back()为例,

 

其中size就是实际存入数据空间的大小,capacity是容量,即能容纳的数据个数。下面看一下push_back()的过程:

在insert_aux里:

这个过程就是容量扩充(备用空间不够了,就重新开辟更大的空间,把旧的拷贝进去,再把旧的释放了,有了更大的新空间,就可以连续的插入和追加元素了

所以这个过程:重新配置->拷贝数据->释放旧的空间

如果每添加一个元素都这样操作,那效率太低了,索性一次多分分配些空间。

但是注意:

1.vector可以用下标访问元素,但是,只能访问size以内的(比如,size=10,capacity=15,就不能arr[12]这样会报错)

2.一旦扩容,原来空间就已经不存在了,数组首地址也不存在了,因为旧的被复制到新的空间,旧的就被释放了。

下面回归正题:size和capacity有什么区别?

size是真实元素的所占的空间打开,capacity是整个可容纳的空间大小;

如第一个图:

size = finish - start

capacity = end_of_storage - start

下面看一下不同编译器capacity大小分配情况:

这是vs2017的运行结果:

        vector<int> arr(10,1);//10个空间,初值都是1
	cout << "size=" << arr.size() << endl;
	cout << "capacity=" << arr.capacity() << endl;

	arr.push_back(2);//向后面添加一个元素2
	cout << "size=" << arr.size() << endl;
	cout << "capacity=" << arr.capacity() << endl;

这是ubantu16,g++ 5.4的运行结果:

为什么capacity一样呢?

这个编译器有关系,在《STL源码剖析》上可以找到答案:

但是再vs2017上,capacity在满的时候,扩充的大小为原来的一半,而不是2倍。

===============================分隔线 2019.7.4=====================================================

【问题】怎么使capacity值为0?

先看代码,再讨论

#include "stdafx.h"
#include<vector>
#include<iostream>
void vector_test()
{
	std::vector<int> arr(10,1);
	std::cout << "arr(10,1):size=" << arr.size() << "; capacity=" << arr.capacity() << std::endl;
	arr.push_back(5);
	std::cout << "arr.push_back(11):size=" << arr.size() << "; capacity=" << arr.capacity() << std::endl;
	arr.clear();
	std::cout << "arr.clear():size=" << arr.size() << "; capacity=" << arr.capacity() << std::endl;
	//arr.resize(0);
	//std::cout << "arr.resize(0):size=" << arr.size() << "; capacity=" << arr.capacity() << std::endl;
	//arr.reserve(0);
	std::cout << "arr.reserve(0):size=" << arr.size() << "; capacity=" << arr.capacity() << std::endl;
	std::vector<int>(arr).swap(arr);
	
	std::cout << "vector<int>(arr).swap(arr):size=" << arr.size() << "; capacity=" << arr.capacity() << std::endl;
}
void Test()
{
	vector_test();
}
int main()
{
	Test();
	getchar();
    return 0;
}

 

 1.为什么要把capacity值变为0?

答:当vector容器不断的插入,capacity也不断的扩张,其实capacity是占着内存的,有时候用不了那么多,岂不是很浪费?所以怎么修改capacity的值,也就是我们手动的释放不使用的空间。capacity变为0只是经常会被问到,变为0都会了,变为其他值就是照猫画虎。

2.怎么变?

利用vector的拷贝构造函数。(1)vector的拷贝构造函数,只分配拷贝的元素需要的内存(2)因为产生临时对象,然后和原来对象进行交换。(3)临时对象消失。

收先验证拷贝构造函数,只分配拷贝的元素需要的内存:

std::vector<int> arr1 = std::vector<int>(arr);
std::cout << "arr1:size=" << arr1.size() << "; capacity=" << arr1.capacity()<<std::endl;

 

然后交换:

交换前需要使用clear,将容器清零。

arr.clear();
std::vector<int> arr1 = std::vector<int>(arr);
arr1.swap(arr);

 也可一步到位:

std::vector<int>(arr).swap(arr);

另外记录一下resize和reserve这两个函数:

resize是调整size的大小,如果size调整到比原来小,capacity的值不会变化;如果size调整的比原来大,则遵循push_back的扩容原则。

reserve是调整预分配空间的大小,如果调整比原来擦capacity小,依然还是原来capacity的大小。

https://www.cnblogs.com/chailu/p/6179263.html

  • 26
    点赞
  • 93
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值