您的位置:首页 > 编程语言

关于STL中vector的内存管理与简单代码实现

2012-11-30 15:38 537 查看
vector 的内部实现其实就是一块连续内存,它和传统的array不同的是支持扩容,不用考虑越界。vector的迭代器就是最简单的指向容器内类型的指针。其内部有三个指针,start(指向数据存储区的首地址),finish(已使用的数据区的尾端),end_of_storage(指向容量尾端,容量一般富余),当遇到满载的情况,finish指针和 end_of_storage 指针相等,也就是容量用完的时候,如果继续插入元素,就会扩容。

需要扩容的时候,空间适配器就会从新寻找一块更大的内存空间(因为vector内部是一块连续的内存),然后start指向新内存首地址,原始数据复制,新数据插入,同时更新finish以及end_of_storage即可。扩容的规模一般是原始容量的两倍。

下面的代码参照 侯捷《STL源码剖析》第四章。意在了解vector的内存管理以及各个接口的实现。出于简单考虑,部分接口没有按照标准做,空间适配器的部分是我自己手动实现的,也没有再做成公共接口,而是直接加在函数实现里面了,可能比较粗糙。

#include<iostream>
using namespace std;

template <class T>
class MyVector{
public:

typedef T * iterator;
typedef T * pointer;
typedef T & reference;

MyVector():start(0),finish(0),end_of_storage(0){}
MyVector(int n,const reference val)//申请n单位空间,并用val初始化
{
start = new T
;
finish = start;
end_of_storage = start + n;
while(n--) { *finish++=val; }
}
MyVector(int n)//申请n单位空间,初始化为0
{
start = new T
;
finish = start;
end_of_storage = start + n;
while(n--) { *finish++=0; }
}

~MyVector(){
iterator i;
for(i=start;i<end_of_storage;i++) i->~T();
}

iterator begin() const { return start; }
iterator end() const { return finish; }

//注意size的定义,返回值是end - begin,也就是说,finish指向的是最后一个元素后面的一个地址
int size() const { return int(end()-begin()); }

//void resize(int new_size,const reference x);//重新定义空间大小,而且完成初始化,finish指针在空间尾端
//void resize(int new_size);
//void reserve(int new_size);//重新定义空间大小,但是不改变finish指针
int capacity() const { return end_of_storage-begin(); }

bool empty() const { return begin() == end(); }

reference operator[](int n) { return *(begin()+n); }
reference front() { return *begin(); }
reference back() { return *(end()-1); }

void push_back(const reference x){
if(finish != end_of_storage)//未满载
{
*finish = x;
finish++;
}
else insert(end(),1,x);//满载,需要重新分配空间,并完成已有成员的搬移
}

void pop_back()//删除尾端元素
{
finish--;
finish->~T();
}

void erase(iterator first,iterator last)//清除[first,last)的所有元素
{
int j = end()-last;
for(int i=0;i<j;i++){
*(first+i) = *(last+i);
}
while(end()>first+j){
pop_back();
}
}

void erase(iterator position)//清除指定位置元素
{
erase(position,position+1);
}

void clear(){//清空vector
erase(begin(),end());
}

void insert(iterator position,int n,const reference x);//从position开始插入n个元素,每个元素的初始值为x
//void insert_aux(iterator position, const reference x);//重新分配空间,并完成已有成员的搬移

private:
iterator start;
iterator finish;
iterator end_of_storage;
};

template <class T>
void MyVector<T>::insert(iterator position,int n,const reference x)//从position开始插入n个元素,每个元素的初始值为x
{
/*
STL的vector<class type>::insert(type * , int , const type &) 作用:在指定位置插入元素,有可能引起扩容
当插入导致finish 指针大于 end_ofstorage 时,就需要扩容
*/

iterator i = start;//old_start
iterator new_finish;//不扩容的话指向old_start,扩容的话指向new_start
iterator old_start = start,old_finish = finish;
bool needToDestory = false;
if(finish+n > end_of_storage){

needToDestory = true;

const int old_size = size();
const int len = old_size + n;

start = new T[len];
new_finish = start;
end_of_storage = start + len;
}
else {
new_finish = start;
end_of_storage = finish + n;
}

/*原始数据的搬移*/
while(i<position) { *new_finish++ = *i++; }
/*插入部分的初始化*/
while(n--) { *new_finish++ = x; }
/*原始数据的搬移*/
while(i<finish) { *new_finish++ = *i++; }
finish = new_finish;

/*这里需要释放原有空间*/
if(needToDestory==true){
while(old_start != old_finish){
old_start->~T();
old_start++;
}
}
}
/*
template <class T>
void MyVector<T>::insert_aux(iterator position,const reference x){
insert(position,1,x);//重新分配空间,并完成已有成员的搬移
}
*/
struct Node{
Node(){}
Node(int a=0,int b=0):x(a),y(b){}
int x,y;
};

int main(){
MyVector<Node> test(3);

cout <<"size of vector now : "<< test.size() << "\t" <<"capacity of vector now : "<< test.capacity() << endl;

for(int i=0;i<3;i++){
Node a(i,i*i);
test.push_back(a);
/*
push_back()是从end()端插入,而初始化过的vector的end()是和capacity()相等的,所以会发生扩容,
也就是说,我们插入的三个点(0,0),(1,1),(2,4)的位置是在a[3],a[4],a[5]中,而a[0],a[1],a[2]中还是初始化时的值,
如果觉得这样浪费的话,想把点插入到最开始的位置的话,有以下几种方法:

NODE 1:可以再申请容器的时候,不指定大小(默认为0),那么后续插入引起扩容,自然就从第一个位置(a[0])开始了
NODE 2:用reserve(N)指定大小,这个函数不会修改finish指针,也就是说,finish指针指向的是begin()端
PS:reserve()接口这里我没有实现,留到以后有时间加上吧
NODE 3:用insert()在指定位置插入点,但是这样会引起扩容
NODE ……欢迎补充 ^_^
*/
}

cout <<"size of vector now : "<< test.size() << "\t" <<"capacity of vector now : "<< test.capacity() << endl;

MyVector<Node>::iterator pi;
for(pi = test.begin();pi != test.end();pi++){
cout << pi->x << " " << pi->y << endl;
}

/******测试insert()******/
test.insert(test.begin(),7,test[5]);//在begin()端插入7个元素,容量变为 size() + 7

cout <<"size of vector now : "<< test.size() << "\t" <<"capacity of vector now : "<< test.capacity() << endl;

MyVector<Node>::iterator pj;
for(pj = test.begin();pj != test.end();pj++){
cout << pj->x << " " << pj->y << endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐