STL与泛型编程<二>:Vector
来源:互联网 发布:怎么和淘宝客服联系 编辑:程序博客网 时间:2024/06/16 22:18
Vector模拟一个动态数组,其内存模型如下
Vector的能力
vector将元素复制到内部的dynamic array中,是一个有序群集;vector支持随机存取,vector迭代器是一个随机存取迭代器 ,所以对任何一个STL算法都可以。
大小(size)和容量(capacity)
为什么vector比容器的通用操作多了个capacity()?就是因为
vector优异性能就是配置比其容纳的元素所需更多的内存。其中capacity()返回vector实际能够容纳的元素数量,如果超越了这个数量,vector就有必要重新配置内部存储器
vector的容量很重要,主要有以下两点
1. 一旦内存重新分配,和vector元素相关的所有references,pointers,iterators都会失效
2. 内存重新配置很耗时间
当然,可以使用reserve()保存适当容量,避免重新分配,且reverse()操作不会改变容器的size和元素
#include <iostream>#include <vector>using namespace std;int main(void){ int arr1[] = {1,2,3}; vector<int> v1(arr1,arr1+sizeof(arr1)/sizeof(arr1[0])); vector<int>::const_iterator it = v1.begin(); cout << "size:" << v1.size() << endl; //3 cout << "capacity:" << v1.capacity() << endl; //3 cout << "begin iterator :" << *it << endl; //1 v1.reserve(80); //reserve后重新分配分配内存空间,所有references,pointers,iterators都会失效 cout << "size:" << v1.size() << endl; //3 cout << "capacity:" << v1.capacity() << endl;//80 cout << "begin iterator :" << *it; //一个杂乱的数字 return 0;} /*如上注释,所有reserve一般在元素还未装入容器中时就调用了,一般也这样使用,在刚创建vector时还未对其容器中元素赋值时进行reversevector<int> v;v.reserve(80);...//赋值操作*/
注意:vector不能使用reserve()来缩减容量,如果reserve()的参数比当前vector的容量还小,则不会产生任何作用。这里有个间接缩减vector容量的小窍门,如下代码
再看一个例子缩减容量的
#include <iostream>#include <vector>using namespace std;template <typename T>void shrinkCapacity(vector<T>& v){ vector<T> tmp(v); v.swap(tmp); }int main(void){ int arr1[] = {1,2,3}; vector<int> v1; v1.reserve(30); v1.assign(arr1,arr1+sizeof(arr1)/sizeof(arr1[0])); vector<int>::const_iterator it = v1.begin(); cout << "before shrinkCapacity :" << endl; cout << "size:" << v1.size() << endl;//3 cout << "capacity:" << v1.capacity() << endl;//30 cout << "begin iterator :" << *it << endl;//1 cout << endl; cout << "after shrinkCapacity :" << endl; shrinkCapacity(v1); cout << "capacity:" << v1.capacity() << endl;//3 cout << "begin iterator :" << *it << endl; //出现的值奇怪 //所以应该更新一下才行 it = v1.begin(); cout << "begin iterator :" << *it << endl;//1 return 0;}
不过注意,swap()后原先所有的references,pointers,iterators都会失效。
甚至可以直接调用
vector<T>(v).swap(v); //其实就是创建一个临时变量与v交换/*vector<T>(v); 创建一个临时变量,并用v进初始化*/
另外一个避免重新分配内存的是,初始化期间就想构造函数传递附加参数
vector<T> v(5); //创建一个有5个值得vector,但是会调用5次default构造函数
如果这样做仅是为了保留足够内存,建议还是使用reserve()。
事实上,为了防止内存破碎,在很多STL版本中,容量的增大幅度很大,即使你不调用reserve(),当你第一次安插元素时,也会一口气配置整块内存(如2K)。
既然vector的容量不会缩减,删除元素,其references,pointers,iterators也会继续有效,然而安插操作可能使其失效(因为安插可能导致vector重新分配空间)
Vector的操作函数
- 构造、拷贝和析构
- 非变动性操作
- 赋值
上图列出了“将新元素赋值给vector,将旧元素全部移除”的方法,所有赋值操作都可能会调用元素型别的default构造函数,copy构造函数 ,assignment操作符和或析构函数 - 元素存取
只有at会进行越界检查,其他函数不做检查 - 迭代器相关函数
- 安插和移除元素
需要注意的是:安插或移除元素都会使“作用点”之后的元素的references,pointers,iterators失效。安插操作若是引得vectro重新分配内存,那么该容器身上的所有references,pointers,iterators都会失效
vector没有提供删除与val相等的所有元素,因此需要借助算法。
栗子,删除与val相等的第一个元素
#include <iostream>#include <vector>#include <algorithm>using namespace std;void print(const vector<int>& v){ vector<int>::const_iterator it = v.begin(); for (; it!=v.end(); ++it) cout << *it << " "; cout << endl; }int main(void){ double val = 3; int arr[] = {1,2,3,4,3,25,3}; vector<int> v(arr,arr+sizeof(arr)/sizeof(arr[0])); print(v); vector<int>::iterator it; //刚开始设置为const_iterator it = find(v.begin(),v.end(),val); if (it != v.end()) v.erase(it); print(v); return 0;}/*犯了一个错误:见标识处,而erase()里的参数中的iterator不是const型的*/
将vector当作一般Arrays使用
简单的说只要你需要动态数组,你就可以使用vector。
看一个例子
#include <iostream>#include <vector>#include <cstring>using namespace std;void print(const vector<char>& v){ for (int i=0; i<v.size(); ++i) cout << v[i] << " "; cout << endl; }int main(void){ vector<char> v; v.resize(40); strcpy(&v[0],"hello"); cout << &v[0] << endl; //cout << v.begin() << endl; 错误,might work, but not portable print(v); return 0;}/*如今vector就像一个连续数组一样,可以通过其首地址&v[0]来打印字符串的值。*/
注意:千万不要把迭代器当作第一元素的地址来传递,vector迭代器是由实作版本定义的,也许不是个一般指针
还有如果要存字符串数组的话,建议用vector.
补充
swap还可以交换元素的值,不止是交换两个容器
#include <iostream>#include <vector>#include <cstring>using namespace std;int main(void){ vector<int> v; v.push_back(2); v.push_back(3); swap(v[0],v[1]); cout << v[0]; cout << v[1];}
总结
vector比容器通用的操作多出以下几个成员函数
capacity(); reserve();assign(n,elem);assign(beg,end);push_back();pop_back();resize();
可以看出:
1. 多出的函数有不少是和容量有关的,所以说弄清楚vector的容量很重要
2. 另外的就是和元素插入删除有关的函数,主要是和vector特性有关,都只在尾部进行相应动作
3. 当然vector也可以在中间插入,但是成本大,不划算
4. vector当容量不足时,一般的实作版本会将容量扩充一倍
错误
由于时常回过头来看看,经常发现问题并记录下来。
- 关于reserve()操作,先看一个例子
#include <iostream>#include <vector>#include <algorithm>#include <functional>#include <iterator>using namespace std;int main(void){ vector<int> col; col.reserve(10); col[0] = 1; col[1] = 2; cout << col[0] << " " << " " << col[1] << endl; copy(col.begin(),col.end(),ostream_iterator<int>(cout," ")); return 0;}/*这代码在DevC++(gcc)和vs08下都能编译通过,但是DevC++下能运行,结果:1 2(当然最后一句打印容器的值是没有值的)在 vs08下运行会出错 */
原因:reserve()操作不会改变容器的元素和容器的size(可通过size()操作返回),而operator[]操作不做边界检查,可能越界,因此编译不会出错,但是运行会出错。
总结:注意STL的大多数操作都不提供边界检查,因此需要特定注意,尤其在对迭代器进行操作时
- STL与泛型编程<二>:Vector
- 泛型编程与STL(二):函数对象
- STL泛型编程学习之vector向量容器
- C++STL泛型编程——vector向量容器
- 泛型编程与STL
- 泛型编程与STL
- STL与泛型编程
- STL与泛型编程
- 泛型编程与STL
- 《泛型编程与stl》
- 泛型编程与STL
- STL系列之二_list与vector的区别
- STL----vector与string
- STL vector与迭代器
- C++ STL vector实现(二)
- STL 学习笔记 ( 二. vector )
- STL vector 使用方法简介 (二)
- stl::vector排序二例
- 爬虫福利:教你爬wap站
- 有关标签和包的知识
- iOS开发笔记之四十五—— Objective-C类扩展的方法之一——分类(category)
- 设计模式之外观模式
- 设计模式之策略模式
- STL与泛型编程<二>:Vector
- 设计模式之备忘录模式
- Spring框架学习之IOC(一)
- Spring框架学习之IOC(二)
- JSON格式之GSON解析
- WebSocket之获取HttpSession
- 简单的Map缓存机制实现
- JS之字符串与JSON转换
- 《深入理解Java虚拟机》笔记