vector是stl中常用的容器类,这里为大家简单介绍下使用方法以及使用时注意的事项。
vector(向量),是模板类,也就是说可以初始化为可储存各种类型的容器,可以是字符型、整数型,以及类类型。
其中储存的元素在内存中是连续的,这点同数组一样,可以提供随机访问。定义的方法如下:
vector<int> vec;
这里定义了一个存储类型为int的vector。注意这时vector的大小不固定,跟编译器有关,有的编译器可能是零,有的可能不是。本人使用的是centos系统,g++的版本为4.8.5,其默认大小如代码运行结果:
#include <iostream>
#include <vector>
using namespace std; //这里为了简单就直接这样打开了命名空间,一般不建议这样做
int main()
{
vector<int> vec;
cout<<vec.capacity()<<endl; //capacity这个成员函数是返回vector实际分配的内存大小
return 0;
}
vector默认大小
向容器中添加数据可以使用其成员函数push_back(),如函数名,是向vector末尾添加数据:
#include <iostream>
#include <vector>
using namespace std; //这里为了简单就直接这样打开了命名空间,一般不建议这样做
int main()
{
vector<int> vec;
vec.push_back(1);
vec.push_back(1);
vec.push_back(2);
vec.push_back(1);
//cout<<vec.capacity()<<endl; //capacity这个成员函数是返回vector实际分配的内存大小
return 0;
}
打印vector中元素
因为使用了C++11,所以在编译的时候应该添加编译选项:--std=c++11。
现在容器中的大小是3?不一定,这个也是根据编译器的不同值也不同,只能说现在容器中有三个元素,其所占用的内存缺不一定。下面用一个例子说明下。
#include <iostream>
#include <vector>
using namespace std;//这里为了简单就直接这样打开了命名空间,一般不建议这样做
int main()
{
vector<int> vec;
for (int i=0; i<5; ++i)
{
vec.push_back(i);
cout<<"num :"<<i<<"--"<<"capacity :"<<vec.capacity()<<endl;
}
return 0;
}
vector所占内存大小
一般来说,当现有空间满了的时候,继续往vector中添加元素时,这时候系统会在另外一块连续空间的内存重新分配一块内存,然后将旧的vector中的元素拷贝到新的vector中,然后释放掉旧的vector。新内存的大小一般是旧的的2倍。如果vector中放的是类类型,那么这将是一个很耗时的过程:复制元素时需要调用容器中元素的构造函数,然后释放旧容器的时候调用其析构函数。所以为了防止元素在内存中“搬来搬去”,一般可以使用的做法是在定义的时候,预先申请一块大点的内存:
#include <iostream>
#include <vector>
using namespace std; //这里为了简单就直接这样打开了命名空间,一般不建议这样做
int main()
{
vector<int> vec;
vec.reserve(6); //调用成员函数reserve进行控制内存分配的大小
for (int i=0; i<5; ++i)
{
vec.push_back(i);
cout<<"num :"<<i<<"--"<<"capacity :"<<vec.capacity()<<endl;
}
return 0;
}
使用reserve成员函数
访问vector中的成员时,可以同数组一样使用[]进行下标访问,但是更推荐使用成员函数at(),因为成员函数at()会进行数组越界检查:如果越界,则抛出异常。
删除容器中的元素可以调用erase()成员函数。注意这个成员函数返回的是指向下个元素的迭代器:
#include <iostream>
#include <vector>
using namespace std; //这里为了简单就直接这样打开了命名空间,一般不建议这样做
int main()
{
vector<int> vec;
vec.reserve(6); //调用成员函数reserve进行控制内存分配的大小
for (int i=0; i<5; ++i)
{
vec.push_back(i);
}
auto it = vec.begin();
cout<<*it<<endl;
it = vec.erase();
cout<<*it<<endl;
return 0;
}
删除元素
清空容器可以使用成员函数clear()。
#include <iostream>
#include <vector>
using namespace std; //这里为了简单就直接这样打开了命名空间,一般不建议这样做
int main()
{
vector<int> vec;
vec.reserve(6);
for (int i=0; i<5; ++i)
{
vec.push_back(i);
}
cout<<vec.size()<<endl;
vec.clear();
cout<<vec.size()<<endl;
return 0;
}
清空vector中元素
但是,当你调用clear()函数后,此时vector所占内存的大小是不是也清空了(为零)?没有!此时vector仍然占据着内存空间。
#include <iostream>
#include <vector>
using namespace std; //这里为了简单就直接这样打开了命名空间,一般不建议这样做
int main()
{
vector<int> vec;
vec.reserve(6);
for (int i=0; i<5; ++i)
{
vec.push_back(i);
}
vec.clear();
cout<<vec.capacity()<<endl;
return 0;
}
vector所占内存大小
要想完全释放其所占的内存空间,这里需要这样做:
#include <iostream>
#include <vector>
using namespace std; //这里为了简单就直接这样打开了命名空间,一般不建议这样做
int main()
{
vector<int> vec;
vec.reserve(6);
for (int i=0; i<5; ++i)
{
vec.push_back(i);
}
vec.clear();
cout<<vec.capacity()<<endl;
vector<int>(vec).swap(vec);
cout<<vec.capacity()<<endl;
return 0;
}
vector.swap()
首先构造一个临时对象,它是vec的副本:这个操作由vector的复制构造函数完成。vector的复制构造函数只为其所复制的对象分配内存,也就是说,复制构造函数只把原来vec里的元素复制到临时的vec副本中,这样操作之后,vec的副本就有了与原vec相同的元素,其所占用的空间就是里面元素的空间,并没有多余的空间。然后调用swap()函数,这样临时容器就变成了之前臃肿的容器,而原来的容器则变成了新构造的、容器大小等于元素个数的容量。因为新构造的是临时变量,所以当离开其作用域的时候,该对象就被释放掉了。这样就完成了“空间转换”,释放掉了多余的内存。