vector深入剖析

来源:互联网 发布:溥仪受审贵族气质知乎 编辑:程序博客网 时间:2024/06/04 19:34

vector

vector的数据安排以及操作方式,与array非常的相似(这里的array是C和C++语言本身就有的,而不是在C11中引进在STL的std::array)。array是静态空间,一旦配置了就不能改变。vector是动态空间,随着元素的增加,它的内部机制会自行的扩充空间以容纳新元素。

vector的构造
(1)vector<int>intVect;`

观察内存可以看到生成一个带有0个元素的vector时内存中start,finish,end_of_storage的值均为0,说明vector对象并没有在堆中分配任何存储空间,仅仅是在栈中分配了16字节存储vecotr对象元素,在这16字节中前4字节如果没猜错,应该是一个虚表指针。因为GNU 4.9版改变了STL的原有的一个class实现一个容器,而是采用了继承和多态的方式。如果是早期版本就应该是4个字节
gnu4.9vector是实现方式

(2)vector<int> intVec(5)
Vector构造对象时只有一个参数时。分配的堆内存空间会默认全部初始化为0;数组的size大小和capacity大小相等。

(3)vector<int> intVec(5,2);`
Vector构造对象时只有两个参数时。分配的堆内存空间会默认全部初始化为第二个参数;数组的size大小和capacity大小相等为第一个参数。

(4)

`vector<int>intVec1 = { 1, 2, 3 };vector<int>intVec2(intVec1)`;

vector的拷贝构造是一个深拷贝,intVec2分配了同intVec1同样大小的内存空间,并把intVec1中的数值拷贝了过来

(5)
C11中新加的构造方式,构造函数接受一个initialize_list参数

 `vector<int>intVec1 = ({ 1, 2, 3 });  vector<int>intVec2 = { 4, 5, 6 };

`通过initialize_list列表中所给的数值以及数值个数分配空间

(6)构造元素为自定义类型的vector

vector<int>Vec1(5);vector<vector<int>>Vec2(5,Vec1);  比如二维数组

同基本数组类型vecotr的构造相似 ;第一个参数:指定元素的个数(数组大小);第二个参数:数组元素全部初始化为第二个参数的值

关于vector的内存释放

vector map set等标准容器默认都是使用内存分配器模板类allocator管理内存的分配、释放。allocator调用new/delete操作符进行批量的内存分配。

由于vector的对象是通过构造函数用分配器在堆上构造的,如果你第一个局部的vector对象也就只有它内部的三个指针在栈上,分配的内存在堆上。
所以当只有你调用对象的析枸函数是才会释放vector的内存,此外还有一种方式就是掉用swap()。所以当vector即使删除了大量数据(或者全部都删除,即clear) 并没有改变容器的容量(capacity),所以仍然会占用着内存。 为了避免这种情况,我们应该想办法改变容器的容量使之尽可能小的符合当前 数据所需(shrink to fit)

《Effective STL》给出的解决方案是:

vector<type> v; //.... 这里添加许多元素给v //.... 这里删除v中的许多元素 vector<type>(v).swap(v); //此时v的容量已经尽可能的符合其当前包含的元素数量 //对于string则可能像下面这样 string(s).swap(s);

即先创建一个临时拷贝与原先的vector一致,值得注意的是,此时的拷贝 其容量是尽可能小的符合所需数据的。紧接着将该拷贝与原先的vector v进行 交换。好了此时,执行交换后,临时变量会被销毁,内存得到释放。此时的v即为原先 的临时拷贝,而交换后的临时拷贝则为容量非常大的vector(不过已经被销毁)

C++ 11里面有扩展,shrink_to_fit 函数可以帮到你,shrink_to_fit 会缩小到适应容器,首先clear,再shrink_to_fit 就ok了。

关于vector一些常用方法
1. v.push_back(t) 在容器的最后添加一个值为t的数据,容器的size变大。
另外list有push_front()函数,在前端插入,后面的元素下标依次增大。
2. v.size() 返回容器中数据的个数,size返回相应vector类定义的size_type的值。v.resize(2*v.size)或 v.resize(2*v.size, 99) 将v的容量翻倍(并把新元素的值初始化为99)
3. v.empty() 判断vector是否为空
4. v[n] 返回v中位置为n的元素
5. v.insert(pointer,number, content) 向v中pointer指向的位置插入number个content的内容。
还有v. insert(pointer, content),v.insert(pointer,a[2],a[4])将a[2]到a[4]三个元素插入。
6. v.pop_back() 删除容器的末元素,并不返回该元素。
7.v.erase(pointer1,pointer2) 删除pointer1到pointer2中间(包括pointer1所指)的元素。vector中删除一个元素后,此位置以后的元素都需要往前移动一个位置,虽然当前迭代器位置没有自动加1,但是由于后续元素的顺次前移,也就相当于迭代器的自动指向下一个位置一样。
8. v1==v2 判断v1与v2是否相等。
9. !=、<、<=、>、>= 保持这些操作符惯有含义。
10. vector::iterator p=v1.begin( ); p初始值指向v1的第一个元素。*p取所指向元素的值。
对于const vector只能用vector::const_iterator类型的指针访问。
11. p=v1.end( ); p指向v1的最后一个元素的下一位置。
12.v.clear() 删除容器中的所有元素。12.v.clear() 删除容器中的所有元素。

0 0