谈一谈C++中的vector容器

 相比于Java,Python等语言而言,C++的容器经常被人鄙视。昨天在知乎上看到大佬们对std::string的口诛笔伐,大致意思就是没有什么灵活的功能诸如split,trim之类,确实也有一定道理。C++毕竟是效率至上的语言,把一些东西留给了程序员们去实现想想也无可厚非。我想不做这些功能,应该也有一点道理吧。
 C++中的vector也是一个很有特点的容器,由于经常写算法的原因经常用到。它相当于一个可变长度的数组,使用起来比普通数组更加灵活且安全,相当时候更推荐使用vector,而非需要new,delete的动态数组。vector可以看作两部分组成,一部分是一个特殊指针,不妨称作“壳”,另一部分是堆中的连续元素数组,不妨称作“核”。因此如果直接sizeof任何一个vector,无论大小,得到的数字是一个很小的定值,也就是壳占用的内存。而核的内存是没法sizeof出来的。
 不同于Java中的Vector或者ArrayList,采用存储地址的方式来添加元素,vector的核存储的都是真值。(当然这个“真值”本身类似指针的情况就是另外一回事了。比如二维vector,大的vector存储的是小的vector的壳而非核,这也是vector本身分两部分的原因,否则vector嵌套的时候存所有的元素,对于内存管理是没有办法实现的)
 CPU访问的元素如果是连续的,那么效率会比随机访问要提高不少,这一点,《C++性能优化指南》讲高速缓存时有所说明。因此,vector的遍历效率是相当快的,至少比Java中类似的容器遍历要快不少。
 存储真值有更重要的优点。Java的Vector等容器,由于存储的是地址,想象把一个对象add进去,再对该对象进行修改,那么Vector里面的内容也会相应发生变化,这不仅不必要而且危险。如果要add对象的副本,则需要额外实现clone方法。但C++的vector就直接做了拷贝。这更符合我们平常的实际需要。如果确实有情况需要,在外部修改容器的内部元素,用vector存储指针也很OK(当然,由于vector内部的增长复制过程,指针的副本可能散落在内存中,为了安全还是用类封装成壳,实现一下析构比较好)。
 有时候我们需要将临时的vector作为参数,之后将原vector销毁。这时候可以采用移动语义的方式。比如vector A作为另一个vector 的push_back的参数

using namespace std;
vector<int> A={3,4,5};
vector<int> V;
V.push_back(move(A));

 这么做的另一个好处是效率。move函数转化左值A为右值,A被重新初始化,在vector/string等库容器的定义中有以右值引用为参数的拷贝构造函数,内部的操作相当于把接收者的壳指向右值的核。(这么说当然不是很严谨,但是理解没问题)
 于是我们可以知道V里第一个vector元素的核,和原来A的核的地址是一样的。(注意,不是元素的地址和A的地址相同)
 直接push_back(A),会调用左值为参数的拷贝构造函数,产生一个新的拷贝,在对象比较大的时候,会有一定开销。

#include<iostream>
#include<vector>
#include<algorithm>
#include<utility>
using namespace std;

vector<int> A={3,4,5};
vector<vector<int>> V;

int main()
{
	cout<<"原来A的元素个数"<<A.size()<<endl;
	cout<<"A的地址是"<<&A<<endl;
	cout<<"A的核的地址是"<<&A[0]<<endl; 
	V.push_back(move(A));
	cout<<"移动之后A的地址是"<<&A<<endl;
	cout<<"现在A的元素个数"<<A.size()<<endl;
	cout<<"V[0]的地址是"<<&V[0]<<endl;
	cout<<"V[0]的核的地址是"<<&V[0][0]<<endl; 
	return 0;
}

 关于移动语义的细节不多言说。凭借移动语义,两个vector的交换swap内部实质上是壳的交换,效率和vector核的大小是无关的。
 一个很实用的操作——完全清空vector并且释放空间

vector<int> E;
vector<int>().swap(E); 

 有时候需要这么做的原因是clear并不保证vector的capacity清零(有可能只是适当缩小,不同编译器有不同处理)。这么做相当于创造临时的vector并与之交换,这样的话,这个临时的右值会被完全回收
 今天先扯到这里。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值