1. vector简介
vector就是一个动态数组,所谓动态指的是它可以自动对内存进行扩展,一般情况下不存在空间不足的情形,(max_size()函数可以知道vector的可以存的最大数量)。而且,我们还不必要去费心地管理内存,这个东西很好用比数组好用多了。所以,只要是用到new T[ ] 来动态分配内存的时候,可以优先考虑使用这个容器。
2.Vector代码解析
部分摘录的代码:
template <class T,class Alloc=alloc>
class vector
{
public:
typedef T value_type;
typedef valuetype* pointer;
typedef valuetype* iterator;
typedef valuetype& reference;
typedef size_t size_type;
....
protected:
iterator start;
iterator finish;
iterator end_of_storage;
....
pubic:
iterator begin{return start;}
iterator end(){return finish;}
size_type size() const {return size_type(end()-begin());}
size_type capacity() const {return size_type(end_of_storage-begin());}
reference front {return *begin()}
}
3.vector使用注意事项
3.1vector中resize()和reserve()区别
resize(n) 这个函数使用当前元素的个数(size),变成n,多去少补,补的时候补默认的初始化值。
resize(n,t) 用当前元素的个数(size),变成n,多去少补,补的时候补t。
reserve(n)
预分配n个元素的存储空间使得容器的容量(capacity)变成n。
为什么要介绍这两个函数呢?我们先看看,vector的内存管理策略
在 vector 对象构造期间,它先分配一个由其实现定义的默认的缓存大小。当 vector 感觉存储空间不够时,它会自动重新分配更多的内存,分配的大小是当前size的2倍,这样在使用vector的随机访问优势的时候,内存分配的负面影响也会降到最低(不然每次要重新申请内存和复制元素,效率低下),如果旧有空间装满,需要申请更大的内存,并且需要把旧有数据搬到新内存去,最后释放原来的内存此时调用析构函数。
画个图:
所以,我们可以使用reserve来避免不必要的重新分配
就是用这个函数在使用容器之前就分配适当的容量,避免不必要的浪费。
3.2 at()函数和 [ ]操作符的区别
一句话来说,at()会抛出异常,而[ ]不会去判断。但at( )的效率会有点低。
比如这样的代码:
vector<int> v;
v.clear();
cout<<v[0]<<endl;;
cout<<at(v)<<endl; //这个就会报出异常
关于[ ]操作符重载的小问题
返回引用和返回值的区别
返回值时, 就会生成a[i]的一个临时变量,当调用完成后这个临时变量就会被销毁,所以不能当左值。
当返回引用时,返回的其实是这个变量的别名,可以重新赋值,注意不要返回临时变量的别名。
3.3 vector中的erase使用陷阱
vector<int> v;
for(vecotr<int>:: iteratoriter=v.begin();iter!=v.end();iter++)
{
if(*iter==3)
v.erase(iter);
}
这样使用是错误的,因为earase结束后,iter变成了野指针,iter++就产生了错误。
erase()返回值是一个迭代器,指向删除元素下一个元素。
应该这样做:
for(vector<int>::iteratorit=v.begin();it!=v.end();)
{
if(*it==3)
it=v.erase(it);
else
it++;
}
remove()算法
remove()算法不会将相应的元素删除,只会能过移动,把原来的数据覆盖
erase()函数会直接将迭代器中的位置删除
当我们有个连续内存的容器时,使用erase-remove方法习惯用法。
v.erase(remove(v.begin(),v.end(),10),v.end());
3.4使用swap()技巧,除去多余的容量
vector<int>(v).swap(v);//使达到没有多余的容量
vector<int>().swap(v);//清空内存
3.5 把vector数据传给指针
vector<int> v;
&v[0];
当然要判空
if(!v.empty()){ //使用&v[0];}
//注意这里要用empty()判断,不要用v.size()==0来判断。
4.vector的使用
我们可以通过继承vector来使用这个优秀的容器
#include<iostream>
#include<vector>
using namespace std;
struct Item{
int id;
int price;
};
class ItemBag:protected vector<Item*>
{
public:
ItemBag(size_t inisize,size_tmaxsize);
virtual ~ItemBag();
public:
void PrintInfo();
public:
int GetFreePos();
int AddItem(Item *pItem);
Item* DelItem(int id);
protected:
size_t m_nInitSize;
size_t m_nMaxSize;
};
ItemBag::ItemBag(size_tinisize,size_t maxsize)
:m_nInitSize(inisize)
,m_nMaxSize(maxsize)
{
this->clear();
this->reserve(m_nMaxSize);
this->resize(m_nInitSize);
}
ItemBag::~ItemBag()
{
for(size_ti=0;i<this->size();++i)
{
Item *pItem=at(i);
if(pItem!=NULL)
delete pItem;
}
}
voidItemBag::PrintInfo()
{
cout<<"背包大小是"<<this->m_nInitSize<<endl;
cout<<"背包容量是"<<this->m_nMaxSize<<endl;
}
intItemBag::GetFreePos()
{
for(size_ti=0;i<this->size();++i)
{
if(at(i)==NULL)
return i;
}
return -1;
}
intItemBag::AddItem(Item* pItem)
{
if(pItem==NULL)
return -1;
int pos=GetFreePos();
if(pos>=0)
{
(*this)[pos]=pItem;
return 0;
}
return -1;
}
Item*ItemBag::DelItem(int id)
{
for(size_ti=0;i<this->size();++i)
{
Item *pItem=at(i);
if(pItem&&pItem->id==id)
{
(*this)[i]=NULL;
return pItem;
}
}
return NULL;
}
int main()
{
ItemBag bag(10,100);
bag.PrintInfo();
Item *pItem=new Item;
pItem->id=0;
pItem->price=12;
bag.AddItem(pItem);
cout<<bag.GetFreePos()<<endl;
return 0;
}