vector是STL中的一种顺序性容器,类似于c语言中的数组,但是比普通数组的在空间的运用上更加的灵活。因为普通数组必须在定义是给定好大小,一旦在使用的过程中觉得空间大小不够用就不能够动态的增长了。vector它随着元素的加入,它的内部机制会自行扩充空间以容纳新元素。
来看下它的空间组织结构:
数据结构定义如下:
template<class T, class Alloc = alloc>
class vector
{
...
protected:
iterator start; //表示目前使用空间的头
iterator finish; //表示目前使用空间的尾
iterator end_of_storage; //表示目前可用的尾
...
};
vector采用的迭代器是随机迭代器,由于其维护的是一个连续的线性空间,其迭代器执行的操作普通指针就可以完成。所以不难理解底层的vector的迭代器其实就是一普通的指针。
来看看vector迭代器的数据结构:
template <class T, class Alloc = alloc>
class vector
{
public:
typedef T value_type;
typedef value_type* iterator;
...
};
vector有多个构造函数,默认的构造函数是构造一个初始长度为0的内存空间。继续向vector中添加元素的时候,如果超过当前的(capacity),则容量会扩充至两倍或者更大。那么问题来了~~~扩充空间是在原有的基础上呢还是重新申请一块空间呢??
答案是后者,vector会把扩充前的数据copy到新的内存空间上,并释放原有的内存空间。这样大动作的copy从效率角度看是很低的。这也是这种内存管理方式的一种缺点!!
有缺点就会有优点,vector的优点就是可进行随机访问支持[]操作符。(相比顺序性容器list)
来看看vector的一些基本操作:
#include<iostream>
using namespace std;
#include<vector>
void main()
{
vector<int> vec;
for (int i = 0; i < 10; i++)
{
vec.push_back(i); //尾部添加一个元素
}
//查看其当前元素的个数和当前分配的容量
cout << "vec.size()=" << vec.size() << "vec.capacity()=" << vec.capacity() << endl;
vec.pop_back(); //删除最后一个元素
cout<<"vec.back() = "<<vec.back()<<endl; //查看当前最后一个元素
cout << "vec.front() = " << vec.front() << endl; //查看当前第一个元素
cout << "vec.at(4) = " << vec.at(4) << endl; //返回下标为n的元素的引用,下标越界会抛出异常
cout << "vec[4] = " << vec[4] << endl; //返回下标为n的元素的引用,n>=vec.size()则函数行为未定义
//迭代器遍历vector容器
vector<int>::iterator it;
for (it = vec.begin(); it != vec.end(); it++)
{
cout << *it << " ";
}
cout << endl;
cout << "vec.empty() : " << vec.empty() << endl;
//在第i+1个元素前面插入a
vec.insert(vec.begin() + 4, 100);
//清除第i+1个元素
vec.erase(vec.begin() + 4);
vec.erase(vec.begin(), vec.begin() + 3);//清除[first,last)中的所有元素
vec.resize(10); //调整vec的size大小
vec.resize(20, 1);
vec.reserve(100); //调整vec的capacity大小
vec.clear(); //清除当前所有元素
cout << vec.size() << " " << vec.capacity() << endl;
}
再来说说vector的细节问题:
- clear()函数是把vector的size清为零,相当于resize(0)。它只是把当前的元素的个数清零,元素在内存并没有消除,所以使用vector的过程中要注意,防止内存泄露。常用的办法是采用swap函数来替换并释放内存。
vector<int> vec;
for(int i=0 ;i<10;i++)
{
vec.push_back(i);
}
vec.swap(vector<int>()); //将容量capacity也释放
2.vector中的reserve()函数和resize()函数的区别
resize()函数和容器的size息息相关,调用resize(n)后,容器的size为n。是否会影响capacity,取决于n的大小如果大于capacity,则会影响capacity的大小。
reserve()函数和容器的capacity息息相关,调用reserve(n)后:
- 若容器的capacity < n ,则重新分配内存空间,使得capacity等于n。
- 若容器的capacity >= n ,则capacity无变化。
-
从函数接口上看,resize()函数有两种,一种是一个参数,一种是两个参数。而reserve()函数只有一种,是一个参数。
从函数用途上看,容器调用resize()函数后,其空间被初始化,可以直接访问,但是reserve()函数预分配出去的空间没有被初始化,所以不可以访问。
3.vector的操作带来的迭代器失效问题
- 向vector中添加元素后,且存储空间被重新分配,则指向容器的迭代器、指针和引用都会失效。若未重新分配空间,则插入位置之后的迭代器指针和引用将会失效。
- 向vector中删除一个元素后,指向被删除元素之前的迭代器、引用和指针仍有效,之后的迭代器无效。