STL源码学习--vector使用方法总结

一、容器vector

使用vector必须包含头文件<vector>:

#include<vector>

型别vector是一个定义于namespace std内的template:

[cpp] view plaincopyprint?

  1. template<class _Ty,
  2. class _Ax = allocator<_Ty> >

第二个参数定义内存模型。我们一般采用默认的内存模型。

二、vector的功能

vector模塑出一个动态数组。vector将其元复制到内部的动态数组中。元素之间总是存在某种顺序,它是一种有序群集。支持随即存取。它的迭代器是随机存取迭代器,所以对任何一个STL算法都奏效。

向vector添加一个元素或者删除其中的一个元素,其后的所有元素都要移动位置,每一次移动都要调用赋值操作符。所以,在末端添加或删除元素,性能很好。但是在前段或者中部的话,性能较差。

vector优异性能的秘诀之一是它配置比其所容纳的元素所需更多的内存。我们需要了解大小容量的关系。

函数size()可以返回vector的大小,即vector中实际元素的个数。

而capacity()返回容量,是当前的vector所实际能够容纳的元素的数量。它应该总是大于或者等于vector的大小。如果需要向vector中放置比capacity更多的元素,则需要重新配置内部存储器。vector的容量也会随之增长。看下面的示例代码:

[cpp] view plaincopyprint?

  1. #include <iostream>
  2. #include <vector>
  3. #include <string>
  4. #include <algorithm>
  5. using namespace std;
  6. int main()
  7. {
  8. vector<string> sentence(1);
  9. cout << "max_size():" << sentence.max_size() << endl;
  10. cout << "size():" << sentence.size() << endl;
  11. cout << "capacity():" << sentence.capacity() << endl;
  12. sentence.reserve(5);
  13. sentence.push_back("Hello,");
  14. sentence.push_back("how ");
  15. sentence.push_back("are ");
  16. sentence.push_back("you ");
  17. sentence.push_back("?");
  18. copy(sentence.begin(),sentence.end(),
  19. ostream_iterator<string>(cout," "));
  20. cout << endl;
  21. cout << "max_size():" << sentence.max_size() << endl;
  22. cout << "size():" << sentence.size() << endl;
  23. cout << "capacity():" << sentence.capacity() << endl;
  24. swap(sentence[1],sentence[3]);
  25. sentence.insert(find(sentence.begin(),sentence.end(),"?"),
  26. "always");
  27. sentence.back() = "!";
  28. copy(sentence.begin(),sentence.end(),
  29. ostream_iterator<string>(cout," "));
  30. cout << endl;
  31. cout << "max_size():" << sentence.max_size() << endl;
  32. cout << "size():" << sentence.size() << endl;
  33. cout << "capacity():" << sentence.capacity() << endl;
  34. }

运行结果:

在程序中,当再次向vector插入元素时,由于vector的容量不够,所以引起了内存的重新分配。但是capacity()的结果与实作版本有关,max_size也是。

vector的容量十分重要,是因为:

1、一旦内存重新配置,与之相关的所有的reference、pointers、iterators都会失效。

2、内存配置很费时。

解决这个问题的方法有:

1、可以使用reserve()保留适当容量,减少重新配置内存的次数。示例代码:

[cpp] view plaincopyprint?

  1. vector<string> sentence(1);
  2. sentence.reserve(50);

2、在初始化期间向构造函数传递附加参数,构造出足够的空间。

[cpp] view plaincopyprint?

  1. vector<T> v(5);

当然,这种元素的型别必须提供默认构造函数。但是如果元素的型别比较复杂,初始化操作也很耗时。如果只是为了保留足够的内存,使用方法1较好。

注意:reserve不能缩减vector的容量。由此,我们可以知道,即使删除元素,其reference、pointers、iterators也会继续有效,指向动作发生前的位置。

但是插入操作可能使reference、pointers、iterators失效(因为可能会导致重新配置空间)。

使用swap函数可以缩减vector容量。因为两个vector交换内容后,他们的容量也会互换。

1、

[cpp] view plaincopyprint?

  1. template<class T>
  2. void shrinkCapacity(vector<T> &v)
  3. {
  4. vector<T> tmp(v);
  5. v.swap(tmp);
  6. }

2、

[cpp] view plaincopyprint?

  1. vector<T>(v).swap(v);

上面两种方法等价。

都是先构造出一个临时vector对象,以v的元素进行初始化,再与v进行交换。需要注意的是:临时对象一般都是精确分配实际所需的内存。所以能够起到减小vector容量的效果。

三、vector的操作函数

所有的构造函数和析构函数如下:

非变动性操作:

赋值操作:

上述操作进行的是将新元素赋值给vector,并将旧元素全部移除!示例代码:

[cpp] view plaincopyprint?

  1. #include <iostream>
  2. #include <vector>
  3. #include <string>
  4. #include <algorithm>
  5. using namespace std;
  6. int main()
  7. {
  8. vector<string> sentence(1);
  9. cout << "max_size():" << sentence.max_size() << endl;
  10. cout << "size():" << sentence.size() << endl;
  11. cout << "capacity():" << sentence.capacity() << endl;
  12. sentence.reserve(5);
  13. sentence.push_back("Hello,");
  14. sentence.push_back("how ");
  15. sentence.push_back("are ");
  16. sentence.push_back("you ");
  17. sentence.push_back("?");
  18. copy(sentence.begin(),sentence.end(),
  19. ostream_iterator<string>(cout," "));
  20. cout << endl;
  21. sentence.assign(3,"new");
  22. copy(sentence.begin(),sentence.end(),
  23. ostream_iterator<string>(cout," "));
  24. cout << endl;
  25. }

运行结果:

可以看出原来的元素全部被删除了。

元素存取

在这几个函数中,唯一进行下标检查的是at函数。

因此,在调用operator[]的时候,必须心理清楚索引是否是有效的。

迭代器相关函数

迭代器失效的两种情况是:

1、在一个较小的位置上删除或者是移动元素。

2、由于容量的变换引起内存重新分配。

插入和移除元素

插入和移除元素,都会使“作用点”之后的各元素的reference、pointers、iterators失效。插入操作还可能引发内存重新分配,那么该容器上的所有的reference、pointers、iterators都会失效。

四、把vector当做一般数组使用

现在的C++标准保证vector的元素必须分布于连续空间中。对于vector中的一个合法索引,满足下列表达式:

&v[i] = &v[0] + i;

我们必须保证vector能够容纳所有数据。如果使用的是C-String,记住最后有个‘\0‘。

只要我们需要一个元素型别为T的数组,就可以采用vector<T>,然后传递第一个元素的地址给它。

注意:千万不要把迭代器当做第一元素的地址来传递。因为vector迭代器是由实作版本定义的,不一定是一个一般指针。

[cpp] view plaincopyprint?

  1. printf("%s",v.begin());//ERROR(might work,but not portable)
  2. printf("%s",&v[0]);//OK
时间: 2024-10-14 18:36:37

STL源码学习--vector使用方法总结的相关文章

STL源码学习(vector篇)

#include <concept_checks.h> #include<stl_allocate.h> /// The vector base class's constructor and destructor allocate ///(but don't initialize) storage. This makes exception safety easier. template <class _Tp, class _Alloc> class _Vector_

STL源码之vector

1. SGI的vector SGI stl vector继承子一个基类: template<typename _Tp, typename _Alloc = std::allocator<_Tp> >     class vector : protected _Vector_base<_Tp, _Alloc> 在基类中定义了基本的一些操作,并且封装了了vector所需要的基本的三个指针: struct _Vector_impl       : public _Tp_all

【STL源码学习】STL算法学习之二

第一章:前言 学习笔记,记录学习STL算法的一些个人所得,在以后想用的时候可以快速拾起. 第二章:明细 copy 函数原型: template <class InputIterator, class OutputIterator> OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result); 函数作用: 将[first,last)区间的元素拷贝至result开头的迭代器区间,并返回赋值

【STL源码学习】std::list类的类型别名分析

有了点模板元编程的traits基础,看STL源码清晰多了,以前看源码的时候总被各种各样的typedef给折腾得看不下去, 将<list>头文件的类继承结构简化如下 #include <xmemory> #include <stdexcept> #define _STD_BEGIN namespace std { #define _STD_END } _STD_BEGIN // 第一个模板参数 template <class _Val_types> class

【STL源码学习】细品vector

第一节:vector简介 vector是一种典型的类模板,使用的时候必须进行实例化. vector的数据存储在数组上,支持随机访问迭代器,支持下标操作[]和at操作,支持手动扩容和自动容量增长. vector是STL中的最常用容器,并支持STL的通用算法. 第二节:vector的迭代器介绍 vector支持iterator.const_iterator.reverse_iterator.const_reverse_iterator,前两个是正向迭代器,后两个是逆向迭代器. 迭代器支持操作:*操作

jQuery源码学习5——工具方法之attr parents sibling clean

(1).attr attr: function(elem, name, value){ var fix = { "for": "htmlFor", "class": "className", "float": "cssFloat", innerHTML: "innerHTML", className: "className" }; if ( fix

jQuery源码学习3——工具方法篇

基本工具方法结构如下: jQuery.extend({ init:function(){}, each:function(){}, className:{ add:function(){}, remove:function(){}, has:function(){}, }, swap:function(){}, css:function(){}, curCSS:function(){}, clean:function(){}, expr:{}, token:[], find:function()

C++ STL源码学习之算法篇

///由于篇幅太长,因此,删去了很多接口,只分析了内部实现,算法对迭代器的要求也被删去 /// search. template <class _ForwardIter1, class _ForwardIter2> _ForwardIter1 search(_ForwardIter1 __first1, _ForwardIter1 __last1, _ForwardIter2 __first2, _ForwardIter2 __last2) { /// Test for empty range

【STL源码学习】STL算法学习之一

第一章:引子 STL包含的算法头文件有三个:<algorithm><numeric><functional>,其中最大最常用的是<algorithm>,今天学习的是<algorithm>包含的算法中的第一部分:非修改顺序操作算法. 接下来学习的算法基于C++11标准,较老的IDE会支持不全面或者部分算法不支持. 第二章:原型解析 如分类名称体现的信息,本节的所有函数都不会修改序列,并且原理上都是顺序遍历迭代器实现的. all_of 函数原型: t