STL-迭代器源码剖析

本文深入探讨STL中的迭代器模式,揭示其作为数据容器高效访问工具的角色。阐述了迭代器的调用接口、类型体系,以及如何通过迭代器保证程序正确调用。此外,还提到了迭代器与模板的关系,特别是IteratorTraits在类型萃取中的关键作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

         在接触了STL后,觉得STL就是一个为效率而生的怪物,而且令人惊讶的是它里面的很多算法和模板对于学C++的人来说是非常有价值去剖析的。

       迭代器(Iterator)模式--提供一种方法,使之能够依序寻访某个聚合物(容器)所含的各个元素,而又无需暴露该聚合物的内部表达方式。
STL的中心思想在于:将数据容器和算法分开,彼此独立设计,最后再以一贴胶合剂(iterator)将它们撮合在一起。

      迭代器是数据结构容器中非常有用的“特殊指针”,在不暴露容器中结构的条件下,可以取出容器里所有的元素。

<span style="font-family:Microsoft YaHei;font-size:14px;">vector<int > v1;
v1.push_back (5);
v1.push_back (4);
v1.push_back (3);
v1.push_back (2);
v1.push_back (1);
// 迭代器遍历顺序表
vector<int >::iterator it = v1 .begin();
for (; it != v1. end(); ++it )
{
cout<<*it <<" ";
}
cout<<endl ;</span>

相信很多人在看STL源码的时候会有很多的疑问,确实STL是大神们写的代码。我们很难去看懂。里面的宏定义和辅助函数我们可以忽略,只把整个框架提取出来,再往框架中不断的添加功能,最后就会成为STL源码。所以我们现在的任务就是提取Iterator的框架。


一:Iterator的调用接口:

<span style="font-family:Microsoft YaHei;font-size:14px;">//通过Distance来计算两个迭代器之间的距离
//通过Category来确定是前向迭代器还是双向迭代器,还是随机迭代器
template<class T, class Distance, class Category,
class Pointer = T*, class Reference = T&>
</span><pre name="code" class="cpp"><span style="font-family:Microsoft YaHei;">struct Iterator
{
	typedef Category CategoryIterator;//迭代器类型
	typedef T ValueType;				//迭代器所指对象的类型
	typedef Distance DifferenceType;	//两个迭代器之间的距离
	typedef Pointer Pointer;			//迭代器所指类型的指针
	typedef Reference Reference;		//迭代器所指类型的引用
};</span>



      这是Iterator的入口,我们可以看到class Iterator中其实没有很多的东西,就是有5个typedef。利用模板传进来的参数CategoryIterator可以提取出迭代器的类型:

二:迭代器的类型:

<span style="font-family:Microsoft YaHei;font-size:14px;">struct InputIteratorTag{};
struct OutputIteratorTag{};
struct ForwardIteratorTag :<span style="color:#ff0000;">public </span>InputIteratorTag{};
struct BidirectionalIteratorTag :<span style="color:#ff0000;">public</span> InputIteratorTag{};
struct RandomAccessIteratorTag :<span style="color:#ff0000;">public </span>InputIteratorTag{};


//Distance是迭代器之间的距离
template<class T,class Distance>
struct InputIterator         //只读迭代器
{
	typedef InputIteratorTag CategoryIterator;
	typedef T ValueType;
	typedef Distance DifferenceType;
	typedef T* Pointer;
	typedef T& Reference;
};
</span><pre name="code" class="cpp"><span style="font-family:Microsoft YaHei;font-size:14px;">template<class T, class Distance>
struct OutputIterator        //只写迭代器
{
	typedef OutputIteratorTag CategoryIterator;
	typedef T ValueType;
	typedef Distance DifferenceType;
	typedef T* Pointer;
	typedef T& Reference;
};</span>

template<class T, class Distance>struct ForwardIterator //前向迭代器{typedef ForwardIteratorTag CategoryIterator;typedef T ValueType;typedef Distance DifferenceType;typedef T* Pointer;typedef T& Reference;};template<class T, class Distance>struct BidirectionalIterator //双向迭代器{typedef BidirectionalIteratorTag CategoryIterator;typedef T ValueType;typedef Distance DifferenceType;typedef T* Pointer;typedef T& Reference;};template<class T, class Distance>struct RandomAccessIterator //随机迭代器{typedef RandomAccessIteratorTag CategoryIterator;typedef T ValueType;typedef Distance DifferenceType;typedef T* Pointer;typedef T& Reference;};


    这5个迭代器中的继承关系使双向迭代器的对象可以传给前向迭代器,随机迭代器的对象可以传给前向迭代器和双向迭代器,它的原理就是“切片规则”。这就是为什么随机迭代器可以随机机访问迭代器的内容。

三:迭代器萃取机

        STL中有那么多的迭代器,它是通过什么保证程序可以正确的调用合适的迭代器呢?

<span style="font-family:Microsoft YaHei;font-size:14px;">template<class Iterator>
struct IteratorTraits       //Iterator类有内嵌类型
{
	typedef typename Iterator::CategoryIterator  IteratorCategory;
	typedef typename Iterator::ValueType ValueType;
	typedef typename Iterator::DifferenceType DifferenceType;
	typedef typename Iterator::Pointer Pointer;
	typedef typename Iterator::Reference Reference;
};</span><pre name="code" class="cpp"><span style="font-family:Microsoft YaHei;font-size:14px;">//偏特化原生的类型,为了原生类型而存在的特化
template<class T>
struct IteratorTraits<T*>
{
	typedef RandomAccessIteratorTag IteratorCategory;
	typedef T ValueType;
	typedef ptrdiff_t DifferenceType;
	typedef T* Pointer;
	typedef T& Reference;
};


//如上
template<class T>
struct IteratorTraits<const T*>
{
	typedef RandomAccessIteratorTag IteratorCategory;
	typedef T ValueType;
	typedef ptrdiff_t DifferenceType;
	typedef const T* Pointer;
	typedef const T& Reference;
};
</span>


        typename关键字告诉编译器Iterator是一个类型,实例化出对象的时候在来编译。这是class关键字不具有的功能。这里有三种类型萃取机,他们分别代表三种不同的类型。

                  内置类型,原生指针类型,const原生指针类型。

<span style="font-family:Microsoft YaHei;font-size:14px;">template <class InputIterator>
inline typename IteratorTraits <InputIterator>::DifferenceType
Distance(InputIterator first, InputIterator last)
{
	//通过传入的InputIterator决定是哪个类型的IteratorCategory对象
	return _Distance(first, last, IteratorTraits <InputIterator>::IteratorCategory());
}


//前向和双向迭代器的Distance函数,都是通过遍历两个迭代器之间的元素实现的
template <class InputIterator>
inline typename IteratorTraits <InputIterator>::DifferenceType
_Distance(InputIterator first, InputIterator last, InputIteratorTag)
{
	IteratorTraits<InputIterator >::DifferenceType n = 0;
	while (first != last) {
		++first; ++n;
	}
	return n;
}

//随机迭代器的distance
template <class RandomAccessIterator>
inline typename IteratorTraits <RandomAccessIterator>::DifferenceType
_Distance(RandomAccessIterator first, RandomAccessIterator last,RandomAccessIteratorTag)
{
	return last - first;
}</span>



<span style="font-family:Microsoft YaHei;">template <class InputIterator, class Distance>
inline void Advance(InputIterator & i, Distance n)
{
	_Advance(i, n, IteratorTraits <InputIterator>::IteratorCategory());
}
template <class InputIterator, class Distance>
inline void _Advance(InputIterator & i, Distance n, InputIteratorTag)
{
	while (n--) ++i;
} 
template <class BidirectionalIterator, class Distance>
inline void _Advance(BidirectionalIterator & i, Distance n,
BidirectionalIteratorTag)
{
	if (n >= 0)
		while (n--) ++i;
	else
		while (n++) --i;
} 
template <class RandomAccessIterator, class Distance>
inline void __Advance(RandomAccessIterator & i, Distance n,
RandomAccessIteratorTag)
{
	i += n;
} </span>
       advance的提取方法和distance相同。



所以我们可以看到,模板是为STL而生的一点都不为过。通过三个萃取机IteratorTraits可以将原生的内置类型自定义的类型分开是萃取机的精华所在。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值