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

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[n];
		finish = start;
		end_of_storage = start + n;
		while(n--) { *finish++=val; }
	}
	MyVector(int n)//申请n单位空间,初始化为0
	{
		start = new T[n];
		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;
}


  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值