C++模板 底层实现stack 实现vector(空间配置器)

函数模板

模板的意义:对类型也可以进行参数化

(1)函数模板 <= 是不进行编译的,因为类型还不知道

template<typename T> //定义一个模板参数列表 
bool compare(T a,T b) //compare是一个函数模板 
{
	return a>b;
}

(2)模板的实例化 <=函数调用点进行实例化

compare<int>(10,20);
compare<double>(10.5,20.5); 

(3)模板函数 <= 才是要被编译器所编译的

bool compare<int>(int a,int b)
{
	return a>b;
}
bool compare<double>(double a,double b)
{
	return a>b;
}

(4)模板的实参推演 =>可以根据用户传入的实参的类型,来推到出模板类型参数的具体类型

compare(20,30);

(5)模板的特例化(专用化)
不是编译器提供的实例化,而是用户提供的实例化
比如下面遍历器的实例化是有问题的

//函数模板 
template<typename T> //定义一个模板参数列表 
bool compare(T a,T b) //compare是一个函数模板 
{
	return a>b;
}
/*
模板函数
bool compare<const char* >(const char*  a,const char*  b)
{
	return a>b;//将地址进行比较,显然有问题
}
*/
 
//函数模板实参的推演 const char* 
compare("aaa","bbb");

需要进行模板特例化

template<typename T> //定义一个模板参数列表 
bool compare(T a,T b) //compare是一个函数模板 
{
	return a>b;
}

//函数模板  提供const char*类型的特例化版本 
template<>
bool compare<const char *>(const char *a,const char *b)
{
	return strcmp(a,b)>0;
}

//函数模板实参的推演 const char* 
compare("aaa","bbb");

(6)非模板函数的重载关系

//函数模板  提供const char*类型的特例化版本 
template<>
bool compare<const char *>(const char *a,const char *b)
{
	return strcmp(a,b)>0;
}
bool compare(const char *a,const char *b)
{
	return strcmp(a,b)>0;
}

compare("aaa","bbb");//编译器优先调用非模板函数
compare<const char*>("aaa","bbb");//编译器调用模板函数

注意:模板代码不能在一个文件中定义,在另外一个文件中使用(模板代码调用之前,一定要看到模板定义的地方,这样,模板才能够进行正常的实例化,产生能够被编译器编译的代码,所以一般模板代码都是放在头文件当中的)

(7)模板非类型参数 =》必须是整数类型(整数或者地址/引用都可以)都是常量

//SIZE就是模板非类型参数 
template<typename T,int SIZE>
void sort(T* arr)
{
	//冒泡排序 
	for(int i=0;i<SIZE-1;++i)
	{
		for(int j=0;j<SIZE-i-1;++j)
		{
			if(arr[j]>arr[j+1])
			{
				int temp = arr[j];
				arr[j] = arr[j+1];
				arr[j+1]=temp;
			}
		}
	}
}

int main()
{
	int arr[] = {12,3,4,5,6,4,3,1};
	const int size = sizeof(arr)/sizeof(arr[0]);
	sort<int,size>(arr);
	for(int val:arr)
	{
		cout<<val<<" ";
	}
} 

函数模板示例代码:

#include<iostream>
#include<string.h> 
#include<vector>
#include<algorithm>
using namespace std;

//函数模板 
template<typename T> //定义一个模板参数列表 
bool compare(T a,T b) //compare是一个函数模板 
{
	return a>b;
}

/*
模板函数 
在函数调用点,编译器用用户指定的类型,从原模板实例化一份函数代码出来
bool compare<int>(int a,int b)
{
	return a>b;
}
bool compare<double>(double a,double b)
{
	return a>b;
}
bool compare<const char* >(const char*  a,const char*  b)
{
	return a>b;
}
*/

//函数模板  提供const char*类型的特例化版本 
template<>
bool compare<const char *>(const char *a,const char *b)
{
	return strcmp(a,b)>0;
}

//非模板函数 
bool compare(const char *a,const char *b)
{
	return strcmp(a,b)>0;
}

int main()
{
	//函数的调用点  进行模板的实例化 
	compare<int>(10,20);
	compare<double>(10.5,20.5); 
	
	//函数模板的推演 
	compare(20,30);
	
	compare<int>(30,40.5);//第二个参数会转为int 

	cout<<compare("aaa","bbb");//调用非模板函数 
	cout<<compare<const char*>("aaa","bbb");//调用模板函数 
} 

类模板(实现stack)

类模板 =>实例化 =>模板类
类模板的选择性实例化 :只会把调用到的成员函数进行实例化,没有调用的不会实例化

//使用类模板实现栈
#include<iostream>
#include<string.h> 
using namespace std;

//类模板 
template<typename T=int>//可以有默认参数 
class SeqStack//模板名称 
{
public:
	//构造和析构函数名不用加<T>,其他出现模板的地方都加上类型参数列表 
	 SeqStack(int size = 10)
	 	:_pstack(new T[size]),
		 _top(0),
		 _size(size)
	 {
	 	
	 }
	 ~SeqStack()
	 {
	 	delete[] _pstack;
	 	_pstack = nullptr;
	 }
	 SeqStack(const SeqStack<T> &stack)
	 	:_top(stack._top)
	 	,_size(stack._size)
	 {
	 	_pstack = new T[_size];
	 	for(int i=0;i<_top;i++)
	 	{
	 		_pstack[i] = stack._pstack[i];
		}
	 }
	 SeqStack<T>& operator=(const SeqStack &stack)
	 {
	 	if(this==&stack)
	 	{
	 		return *this;
		}
		delete[] _pstack;
		
		_top = stack._top;
		_size = stack._size;
		for(int i=0;i<_top;i++)
	 	{
	 		_pstack[i] = stack._pstack[i];
		}
		return *this; 
	 }
	 void push(const T &val)//入队 
	 {
	 	if(full())expand();
		_pstack[_top++] = val; 
	 }
	 void pop()//出队 
	 {
	 	if(empty())return;
	 	--_top;
	 }
	 T top() const//返回栈顶元素 
	 {
	 	if(empty())
	 	{
	 		throw "stack is empty!";//抛出异常代表函数逻辑结束	
		}
		return _pstack[_top-1];
	 }
	 bool full()const//栈满 
	 {
	 	return _top == _size;
	 }
	 bool empty()const//栈空 
	 {
	 	return _top==0; 
	 }
private:
	T *_pstack;//栈帧 
	int _top;//栈顶指针 
	int _size; //栈的内存空间 
	
	//顺序栈底层数组按2倍的方式扩容 
	int expand()
	{
		T *ptmp = new T[_size*2];
		for(int i=0;i<_top;i++)
	 	{
	 		ptmp[i] = _pstack[i];
		}
		delete[] _pstack;
		_pstack = ptmp;
		_size*=2;
	}
};
int main()
{
	//类模板的选择性实例化 
	//模板类 class SeqStack<int>{}; 
	SeqStack<int> stack;
	stack.push(1);
	stack.push(2);
	stack.push(3);
	while(!stack.empty())
	{
		cout<<stack.top();
		stack.pop();
	}
} 

空间配置器(实现vector)

容器的空间配置器allocator负责:内存开辟/内存释放 对象构造/对象析构
大白话就是:将对象的构造和内存开辟,析构和内存释放分开
为了防止某些情况直接使用 new int[]delete[] ptr 会出现误操作,因为new不仅会开辟内存还有调用构造函数,delete不仅释放内存还有调用析构函数(比如vector底层构造函数和开辟内存并不是同步进行的)
allocator底层实现:

//空间配置器 (和C++标准库的allocator实现一言)
template<typename T>
struct Allocator
{
	T* allocator(size_t size)//负责内存开辟 
	{
		return (T*)malloc(sizeof(T)*size);
	}
	void deallocate(void *p)//负责内存释放 
	{
		free(p);
	}
	void construct(T *p,const T &val)//负责构造 
	{
		new (p) T(val);//定位new  在指定的内存上 构造一个值为val的对象,会调用 T类型的拷贝构造 
	}
	void destroy(T *p)//负责对象析构 
	{
		p->~T();//~T()代表了T类型的析构函数 
	}
};

手写vector

#include<iostream>
#include<vector>
using namespace std;

//空间配置器 (和C++标准库的allocator实现一言)
template<typename T>
struct Allocator
{
	T* allocator(size_t size)//负责内存开辟 
	{
		return (T*)malloc(sizeof(T)*size);
	}
	void deallocate(void *p)//负责内存释放 
	{
		free(p);
	}
	void construct(T *p,const T &val)//负责构造 
	{
		new (p) T(val);//定位new  在指定的内存上 构造一个值为val的对象,会调用 T类型的拷贝构造 
	}
	void destroy(T *p)//负责对象析构 
	{
		p->~T();//~T()代表了T类型的析构函数 
	}
};
/*
容器底层内存开辟,内存释放,对象构造和析构,都通过allocator空间配置器来实现 
*/
//类模板 
template<typename T,typename Alloc = Allocator<T>>
class vector
{
public:
	vector(int size=10)	
	{
		//需要把内存开辟和对象构造分开处理 
		//_first = new T[size];
		_first = _allocator.allocator(size);//仅开辟内存 
		_last = _first;
		_end = _first+size;
	}
	~vector()
	{
		//析构容器有效的元素,然后释放_fisrt指针指向的堆内存 
		//delete[] _first;
		for(T *p = _first;p!=_last;++p)
		{
			_allocator.destroy(p);//_first指针指向的数组的有效元素进行析构操作 
		}
		_allocator.deallocate(_first);//释放堆上的数组内存 
		_first = _last = _end =nullptr;
	}
	vector(const vector& rhs)
	{
		int size = rhs._end - rhs.first;
		//_first = new T[size];
		_first = _allocator.allocate(size); //开辟空间 
		int len = rhs._last-rhs._last;
		for(int i=0;i<len;i++)
		{
			//_first[i] = rhs._first[i];
			_allocator.construct(_first+i,rhs._first[i]);
		}
		
		_last = _first + len;
		_end = _first + size;
	}
	vector& operator=(const vector<T>& rhs)
	{
		if(this==&rhs)return *this;
		
		//delete[] _first; 
		for(T *p = _first;p!=_last;++p)
		{
			_allocator.destrory(p);//_first指针指向的数组的有效元素进行析构操作 
		}
		_allocator.deallocate(_first);//释放堆上的数组内存 
		
		int size = rhs._end - rhs.first;
		//_first = new T[size];
		_first = _allocator.allocate(size); //开辟空间 
		int len = rhs._last-rhs._last;
		for(int i=0;i<len;i++)
		{
			//_first[i] = rhs._first[i];
			_allocator.construct(_first+i,rhs._first[i]);
		}
		
		_last = _first + len;
		_end = _first + size;
		return *this; 
	}
	void push_back(const T &val)
	{
		if(full())expand();
		//*_last++ = val;
		_allocator.construct(_last,val);//_last指针指向的内存构造一个值为val的对象 
		_last++; 
	}
	void pop_back()
	{
		if(empty())return;
		//--_last;
		--_last;//不仅要把_last指针--,还需要析构删除的元素 
		_allocator.destroy(_last);
	}
	T back() const
	{
		return *(_last-1);
	}
	bool full() const
	{
		return _last == _end;
	}
	bool empty() const
	{
		return _first==_last;
	}
	int size() const
	{
		return _last - _first;
	}
private:
	T* _first;//指向数组起始的位置 
	T* _last;//指向数组中有效元素的后继位置 
	T* _end;//指向数组空间的后继位置
	Alloc _allocator;//定义容器的空间配置器对象 
	
	void expand()//二倍扩容 
	{
		int size = _end - _first;
		//T* ptmp = new T[2*size];
		T *ptmp = _allocator.allocator(2*size);//开辟空间 
		for(int i=0;i<size;i++)
		{
			//ptmp[i] = _first[i];
			_allocator.construct(ptmp+i,_first[i]);//在 ptmp+i 位置构造值为 _first[i]的对象 
		}
		//delete[] _first;
		for(T *p=_first;p!=_last;++p)//把有效元素析构 
		{
			_allocator.destroy(p);
		}
		_allocator.deallocate(_first);//释放空间 
		_first = ptmp;
		_last = _first+size;
		_end = _first + 2*size;
	}	 
}; 

class Test
{
public:
	Test()
	{
		cout<<"Test()"<<endl;
	}
	Test(const Test& tst)
	{
		cout<<"Copy Test()"<<endl;
	} 
	~Test()
	{
		cout<<"~Test()"<<endl;
	}
};

int main()
{
	Test t1,t2,t3;
	cout<<"----------------------------"<<endl;
	vector<Test> vec;//仅开辟一段内存 
	vec.push_back(t1);//拷贝构造一个对象 
	vec.push_back(t1);//拷贝构造一个对象 
	vec.push_back(t1);//拷贝构造一个对象 
	cout<<"----------------------------"<<endl;
	vec.pop_back();//仅析析构末尾有效对象,不释放内存
	 cout<<"----------------------------"<<endl;
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值