STL容器vector

来源:互联网 发布:如何删掉mac上的软件 编辑:程序博客网 时间:2024/06/07 16:24

Vector

定义于头文件<vector>

template<    class T,class Allocator = std::allocator<T>> class vector;

Vector的能力

Vector支持随机访问,因此只要知道位置,就可以在常亮时间内访问任意元素。vector提供随机访问迭代器,所以适用于任意STL算法。capacity函数返回vector实际容纳量,如果超过这个量,vector必须重新分配内部内存。一旦内存重新分配,vector元素相关的所有reference、pointer和iterator都会失效,内存重新分配很耗时间。
你可以使用reserve函数保存适当容量,避免重新分配:

std::vector<int> v;v.reserve(80);//reserve mempry for 80 elements

vector不能使用reserve缩减容量,调用reverse所给的实参如果小于当前vector的容量,不会引发任何效果。,既然vector的容量不会缩减,我们就可以知道,及时删除元素,其reference、pointer和iterator也会继续有效,继续指向动作发生前的位置。然而安插动作可能会使reference、pointer和iterator实效,因为会使vector重排。
C++11引入一个新的函数shrink_to_fit:这个函数不具有强制力的要求,可以缩减容量以符合当前的元素个数。

v.shrink_to_fit();//注意不具有强制性

在c++11之前有一个小技巧实现这个功能。

template<typename T>void shrinkCapacity(std::vector<T>& v){    std::vector<T> tmp(v);    v.swap(tmp);}

你甚至可以像这样使用:

std::vector<T>(v).swap(v);

但是要注意的是,这些做法都会使reference、pointer和iterator换了只想对象。

Vector的操作

元素访问
at 访问指定的元素,同时进行越界检查
operator[] 访问指定的元素
front 访问第一个元素
back 访问最后一个元素
data 返回指向内存中数组第一个元素的指针
当pop_back调用时,确保容器不为空是程序员的责任。例如:

std::vector<Elem>coll;if(!coll.empty()){    coll.pop_back();}

关于效能,以下几种情况你可以预期安插动作和移除动作会快一些:
1. 在容器的尾部安插或移除元素
2. 容器的容量一开始就很大
3. 安插多个元素调用一次肯定是最快的

Vector并能没有提供任何函数可以直接移除“与某个值相等”的所有元素。但是可以通过以下做法。

std::vector<Elem> coll;coll.erase(remove(coll.begin(),coll.end(),                    val),            coll.end());

如果只要一出第一个元素,可以这么做:

std::vector<Elem> coll;pos = find(coll.begin(),coll.end(),            val);if(pos != coll.end()){    coll.erase();}

将vector当做C-Style Array使用

reserve是容器预留空间,但并不真正创建元素对象,在创建对象之前,不能引用容器内的元素,因此当加入新的元素时,需要用push_back()/insert()函数。
resize是改变容器的大小,并且创建对象,因此,调用这个函数之后,就可以引用容器内的对象了,因此当加入新的元素时,用operator[]操作符,或者用迭代器来引用元素对象。

std::vector<char> v;v.resize(41);strcpy(&v[0],"hello world");printf("%s\n", &v[0]);

初次接触这两个接口也许会混淆,其实接口的命名就是对功能的绝佳描述,resize就是重新分配大小,reserve就是预留一定的空间。这两个接口即存在差别,也有共同点。下面就它们的细节进行分析。
为实现resize的语义,resize接口做了两个保证:
一是保证区间[0, new_size)范围内数据有效,如果下标index在此区间内,vector[indext]是合法的。
二是保证区间[0, new_size)范围以外数据无效,如果下标index在区间外,vector[indext]是非法的。
reserve只是保证vector的空间大小(capacity)最少达到它的参数所指定的大小n。在区间[0, n)范围内,如果下标是index,vector[index]这种访问有可能是合法的,也有可能是非法的,视具体情况而定。
resize和reserve接口的共同点是它们都保证了vector的空间大小(capacity)最少达到它的参数所指定的大小。

Class vector<bool>

vector<bool>特化版的内部只是用1bit存放元素,空间节省8倍。C++的最小可定址值是以byte为单位的,所以reference和iterator做特殊处理
vector<bool>无法满足其他vector的所有规定,例如vector<bool>::reference并不是一个lvalue,vector<bool>::iterator 也不是一个随机访问迭代器,而且它的操作速度会比一般的vector慢因为他是bit操作。
flip函数用来取补数(complement)。注意,你可以对vector内的所有bit或单一bit调用filp,后者很值得注意,因为你也许会以为subscript操作符返回bool在对此基础类型调用filp是不可能的。然而vector<bool>运用了一个名为proxy的技巧:面对一个vector<bool>,subscript操作符的返回类型实际上是个辅助类,一旦你要求返回值为bool,便会触发一个自动类型转换函数。
所有用于元素访问的函数,返回的都是reference类型。所以可以这么写:

c.front().filp();c[5] = c.back();

只有vector<bool>的non-const容器才会用到内部的proxy类型reference。而用来处理那些const成员函数,返回类型都是const reference,那就是bool。

原创粉丝点击