动机

我们知道STL实现了很多算法(#include<algorithm>),如果项目是基于STL构建那么能够最大化使用现有代码当然是最好的。在STL中容器算法之间的桥梁是迭代器。所以在定义好自定义类型的容器后,接下来就是迭代器的实现。

STL中的迭代器

迭代器模式是一种经典的设计模式,而STL的迭代器实现用到了模板的一些特性和技能,其中的细节可以去参考《STL源码剖析》里面的内容,在这里稍微介绍一下

下面是STL中结构体iterator的定义,这么定义是给后面的算法多态和萃取时(具体见书中介绍)使用的。其中的_Category 和_Ty 没有默认值,需要自己给参数的。_Ty就是元素的类型

template<class _Category,
	class _Ty,
	class _Diff = ptrdiff_t,
	class _Pointer = _Ty *,
	class _Reference = _Ty&>
	struct iterator
	{	// base type for iterator classes
	typedef _Category iterator_category;
	typedef _Ty value_type;
	typedef _Diff difference_type;
	typedef _Diff distance_type;	// retained
	typedef _Pointer pointer;
	typedef _Reference reference;
	};

而_Category是迭代器的类型,主要有以下几种

//	ITERATOR STUFF (from <iterator>)
// ITERATOR TAGS (from <iterator>)
struct input_iterator_tag //只读
	{	// identifying tag for input iterators
	};

struct _Mutable_iterator_tag //只写
	{	// identifying tag for mutable iterators
	};

struct output_iterator_tag  //只写
	: _Mutable_iterator_tag
	{	// identifying tag for output iterators
	};

struct forward_iterator_tag //前向移动
	: input_iterator_tag, _Mutable_iterator_tag
	{	// identifying tag for forward iterators
	};

struct bidirectional_iterator_tag //可双向移动
	: forward_iterator_tag
	{	// identifying tag for bidirectional iterators
	};

struct random_access_iterator_tag //随机读写
	: bidirectional_iterator_tag
	{	// identifying tag for random-access iterators
	};

//...

自定义迭代器

我希望迭代器有以下操作:*,++。另外还想要通过迭代器调用count_if函数。那看一下count_if都用到哪些操作符吧

// TEMPLATE FUNCTION count_if
template<class _InIt,
	class _Pr> inline
	typename iterator_traits<_InIt>::difference_type
		_Count_if(_InIt _First, _InIt _Last, _Pr _Pred)
	{	// count elements satisfying _Pred
	typename iterator_traits<_InIt>::difference_type _Count = 0;

	for (; _First != _Last; ++_First)
		if (_Pred(*_First))
			++_Count;
	return (_Count);
	}

可以看到用到了++,!=,*。所以我们的迭代器需要把这些都给实现了。代码很简单:

#include<iterator>
template<class T>
class MyIterator : public iterator<input_iterator_tag, T>{
	public:
		MyIterator(T* p){
			_ptr = p;
	}
	//赋值
	MyIterator& operator = (const MyIterator &iter)
	{
		_ptr = iter._ptr;
	}
	//不等于
	bool operator != (const MyIterator &iter)
	{
		return _ptr!= iter._ptr;
	}
	//等于
	bool operator == (const MyIterator &iter)
	{
		return _ptr == iter._ptr;
	}
	//前缀自加
	MyIterator& operator ++ ()
	{
		_ptr++;
		return *this;
	}
	//后缀自加
	MyIterator operator ++ (int)
	{
		MyIterator tmp= *this;
		_ptr++;
		return tmp;
	}
	//取值
	T& operator * ()
	{
		return *_ptr;
	}

	private:
	T* _ptr;//实际的内容指针,通过该指针跟容器连接
};

自定义容器

下面给出个简单的数组容器,实现了数组的基本操作。并把刚刚定义的迭代器内置了

template<class T>
class myVector{
public:
	typedef MyIterator<T> iterator;//所有类型迭代器用同一个名字,便于写出更通用的代码
	myVector(){
		_selfElems = new T[32];
		_count = 32;
		init();
	}
	myVector(int n){
		_selfElems = new T[n];
		_count = n;
		init();
	}
	void init(){
		memset(_selfElems, 0, sizeof(T)* _count);
	}

	//常用接口
	T& operator[](int i){
		return _selfElems[i];
	}
	iterator begin(){
		return iterator(_selfElems);
	}
	iterator end(){
		return iterator(_selfElems + _count);
	}
	int size() const {
		return _count;
	}
private:
	T* _selfElems;
	int _count;
};

##测试

定义一个vector和自定容器myVector,用迭代器去访问,并通过迭代器使用conunt_if函数,可以看到用法完全一样

bool eq_10(int k){
	return k == 10;
}

int main(){
	//自定义类型
	myVector<int> mv(10);
	mv[3] = 10; mv[9] = 10;
	myVector<int>::iterator it = mv.begin();
	cout <<"mv:"<<endl;
	while (it != mv.end()){
		cout << *(it++) << " ";
	}
	cout << endl;
	cout << count_if(mv.begin(), mv.end(), eq_10) << endl;

	//STL 容器
	vector<int> v(10,0);
	v[3] = 10; v[9] = 10;
	vector<int>::iterator it1 = v.begin();
	cout << "v:" << endl;
	while (it1 != v.end()){
		cout << *(it1++) << " ";
	}
	cout << endl;
	cout << count_if(mv.begin(), mv.end(), eq_10) << endl;
	getchar();
	return 0;

总结和思考

所以简单来说,如果想要定义自己容器的迭代器并想通过迭代器调用STL的算法函数的话。首先继承iteroter,然后实现必要的操作符即可。不过具体的算法函数对迭代器类型是有要求的,这个需要自己把握。

在这个简单的示例里面,直接用myVector的指针(mv._ptr)也是可以调用count_if的,因为STL通过模板偏特化技术使得迭代器也支持原生指针。不过既然把访问元素都放到迭代器中了,我们就可以对所有的容器用统一的方式访问了,而不用暴露每个容器的细节(myVector::_ptr):

//T为某种迭代器
template<class T>
void display(T it, T end){
	T it1 = it;
	while (it1 != end){
		cout << *(it1++) << " ";
	}
	cout << endl;
	cout << count_if(it,end, eq_10) << endl;
}

int main(){
	//自定义类型
	myVector<int> mv(10);
	mv[3] = 10; mv[9] = 10;
	//STL 容器
	vector<int> v(10, 0);
	v[3] = 10; v[9] = 10;
	//vector 和 myVector底层实现有很大区别,但是可用同一个函数做遍历等操作
	display(mv.begin(), mv.end());
	display(v.begin(), v.end());
	getchar();
	return 0;
}

迭代器赋予了容器更多的功能和通用性

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐