在STL的思想中,容器和算法是彼此独立设计的,再通过某种方式使它们连接;而迭代器是使算法独立于使用的容器类型,即迭代器是连接算法和容器的方法。由于迭代器是一种行为类似指针的对象,也就说迭代器是一种广义指针,即迭代器对解除引用操作(operator*)和访问成员操作(operator->)进行重载。然而要对这两个操作符进行重载,对容器内部对象的数据类型和存储结构有所了解,于是在 STL 中迭代器的最终实现都是由容器本身来实现的,每种容器都有自己的迭代器实现。本文介绍的不是针对某种特定的容器。
在SGI STL中根据读写和访问方式,在源码中迭代器大致可分为五类:
输入迭代器input_iterator: 只读,且只能一次读操作,支持操作:++p,p++,!=,==,=*p,p->;
输出迭代器output_iterator: 只写,且只能一次写操作,支持操作:++p,p++;
正向迭代器forward_iterator: 可多次读写,支持输入输出迭代器的所有操作;
双向迭代器bidirectional_iterator: 支持正向迭代器的所有操作,且支持操作:--p,--p;
随机访问迭代器random_access_iterator: 除了支持双向迭代器操作外,还支持:p[n],p+n,
n+p,p-n,p+=n,p-=n,p1-p2,p1<p2,p1>p2,p1>=p2,p1<=p2;
代码继承关系:
//五种迭代器,作为标记型别(tag types),不需要任何成员
struct input_iterator_tag{};
struct output_iteratoe_tag{};
struct forward_iterator_tag : public input_iterator_tag{};
struct bidirectional_iterator_tag : public forward_iterator_tag{};
struct random_access_iterator_tag : public bidirectional_iterator_tag{};
五种迭代器类型数据类型之一:
templateT,class Distance>
struct input_iterator
{
typedef input_iterator_tag iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef T* pointer;
typedef T& reference;
};
... ...
在STL的算法设计中需要迭代器的型别,根据不同要求和不同型别,有不同的技巧解决;如:使用模板参数推导机制推导出局部变量类型;内嵌型别求出返回值类型;traits技术解决返回值类型和偏特化traits技术解决原生指针问题;迭代器的型别如下代码所示:
template<class Iterator>
struct iterator_traits
{
typedef typename Iterator::iterator_category iterator_category;
typedef typename Iterator::value_type value_type;
typedef typename Iterator::difference_type difference_type;
typedef typename Iterator::pointer pointer;
typedef typename Iterator::reference reference;
}
通过Traits技术我们可以获得迭代器的相关类型的信息iterator_traits<…>::…,下面给出Traits技术的相关源码:
//为避免写代码时挂一漏万,自行开发的迭代器最好继承自下面这个 std::iterator
template<class Category,class T,class Distance=ptrdiff_t,class Pointer=T*,class Reference=T&>
struct iterator
{
typedef Category iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef Pointer pointer;
typedef Reference reference;
}
//针对原生指针(naive pointer)而设计的traits偏特性化版本
template<class T>
struct iterator_traits
{
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef T& reference;
};
//针对Pointer-to-const而设计的traits偏特化版本
template<class T>
struct iterator_traits<const T*>
{
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef const T* pointer;
typedef const T reference;
};
在迭代器中,为了能够在编译时确定函数调用,应用了函数重载。因为五种迭代器操作能力是不同的,例如random acess iterator是操作能力最强的,可以在O(1)时间操作指定位置,而这个用其他的迭代器可能需要O(n)。所以为了提高效率,使用迭代器类型最匹配的算法函数去调用:
1.首先通过traits技术获得迭代器类型iterator_category;
2.在函数调用时生成相应迭代器类型的临时对象作为实参传递,编译器就会调用相应的重载函数。
为了重载函数识别,SGI STL有对应的5种迭代器标识类:继承是为了可以使用传递调用,当不存在某种迭代器类型匹配时编译器会依据继承层次向上查找进行传递。
/*五中迭代器类型*/
struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidirectional_iterator_tag {};
例如下面是advance()函数的调用,针对不同的迭代器类型,对函数进行重载:
/*函数重载,使迭代器能在编译时期就确定调用哪个函数*/
template <class _InputIter, class _Distance>
/*迭代器类型为input_iterator_tag的函数定义*/
inline void __advance(_InputIter& __i, _Distance __n, input_iterator_tag) {
while (__n--) ++__i;
}
template <class _BidirectionalIterator, class _Distance>
/*迭代器类型为bidirectional_iterator_tag的函数定义*/
inline void __advance(_BidirectionalIterator& __i, _Distance __n,
bidirectional_iterator_tag) {
__STL_REQUIRES(_BidirectionalIterator, _BidirectionalIterator);
if (__n >= 0)
while (__n--) ++__i;
else
while (__n++) --__i;
}
template <class _RandomAccessIterator, class _Distance>
/*迭代器类型为random_access_iterator_tag的函数定义*/
inline void __advance(_RandomAccessIterator& __i, _Distance __n,
random_access_iterator_tag) {
__STL_REQUIRES(_RandomAccessIterator, _RandomAccessIterator);
__i += __n;
}
template <class _InputIterator, class _Distance>
/*决定调用哪个函数,这是一个对外接口*/
inline void advance(_InputIterator& __i, _Distance __n) {
__STL_REQUIRES(_InputIterator, _InputIterator);
__advance(__i, __n, iterator_category(__i));
}
利用迭代器种类更有效的实现distance函数,有了前面的基础,我们可以根据不同迭代器种类实现distance函数:
template<class InputIterator>
inline typename std::iterator_traits ::difference_type
distance(InputIterator first, InputIterator last)
{
return __distance(first, last, std::iterator_traits ::iterator_category());
}
template<class InputIterator>
{
std::iterator_traits ::difference_type n = 0;
while (first != last)
{
++first; ++n;
}
return n;
}
template<class InputIterator>
inline typename std::iterator_traits ::difference_type \
__distance(InputIterator first, InputIterator last, std::random_access_iterator_tag)
{
return last - first;
}
前面介绍的Traits技术在STL中弥补了C++模板的不足,但是在STL中,Traits技术只是用来规范迭代器,对于迭代器之外的东西没有加以规范。因此,SGI将该技术扩展到迭代器之外的东西,称为__type_traits。
iterator_traits是萃取迭代器的特性,而_type_traits是萃取型别的特性。
萃取的型别如下:
1. 是否具备non-trivial default ctor?
2. 是否具备non-trivial copy ctor?
3. 是否具备non-trivial assignment operator?
4. 是否具备non-trivial dtor?
5. 是否为POD(plain old data)型别?
其中non-trivial意指非默认的相应函数,编译器会为每个类构造以上四种默认的函数,如果没有定义自己的,就会用编译器默认函数,如果使用默认的函数,我们可以使用memcpy(),memmove(),malloc()等函数来加快速度,提高效率。
定义在SGI type_traits.h 中的_type_traits,提供了一种机制,针对不同型别的特性,在编译时期完成函数派送决定。
/*
*萃取传入的T类型的类型特征
*/
template
struct _type_traits
{
typedef _false_type has_trivial_default_constructor;
typedef _false_type has_trivial_copy_constructor;
typedef _false_type has_trivial_assignment_operator;
typedef _false_type has_trivial_destructor;
typedef _false_type has_POD_type;
};
其中返回真假的“对象”是:
struct _true_type{};
struct _false_type{};
将bool, char, short, int, long, float, double等基本的数据类型及其相应的指针类型的这些特性都定义为__true_type,这意味着,这些对基本类型进行构造、析构、拷贝、赋值等操作时,都是使用系统函数进行的。而除了这些类型之外的其他类型,除非用户指定了它的这些特性为__true_type,默认都是 __false_type 的,不能直接调用系统函数来进行内存配置或赋值等,而需要调用该类型的构造函数、拷贝构造函数等。
template<>
struct _type_traits
{
typedef _true_type has_trivial_default_constructor;
typedef _true_type has_trivial_copy_constructor;
typedef _true_type has_trivial_assignment_operator;
typedef _true_type has_trivial_destructor;
typedef _true_type has_POD_type;
};
... ...
1. Traits编程技法对迭代器加以规范,利用C++重载机制和参数推导机制将运行期决议问题提前到编译期决议,获得了对象的类型
相关信息,从而使得算法可以通过类型信息来优化效率。
2. 使用重载函数来解决if-else条件在编译时期和运行时期的不同步,使其能在编译时期确认调用哪个函数。
3. SGI对traits进行扩展,使得所有类型都满足traits编程规范,这样SGI STL算法可以通过__type_traits获取类型信息后。
iterator.h
#ifndef _ITERATOR_H_
#define _ITERATOR_H_
#include
namespace EasySTL
{
//五种迭代器,作为标记型别(tag types),不需要任何成员
struct input_iterator_tag{};
struct output_iteratoe_tag{};
struct forward_iterator_tag : public input_iterator_tag{};
struct bidirectional_iterator_tag : public forward_iterator_tag{};
struct random_access_iterator_tag : public bidirectional_iterator_tag{};
template<class T,class Distance>
struct input_iterator
{
typedef input_iterator_tag iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef T* pointer;
typedef T& reference;
};
template<class T,class Distance>
struct output_iterator
{
typedef output_iterator_tag iterator_category;
typedef void value_type;
typedef void difference_type;
typedef void pointer;
typedef void reference;
};
template<class T,class Distance>
struct forward_iterator
{
typedef forward_iterator_tag iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef T* pointer;
typedef T& reference;
};
template<class T,class Distance>
struct bidirectional_iterator
{
typedef bidirectional_iterator_tag iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef T* pointer;
typedef T& reference;
};
template<class T,class Distance>
struct random_access_iterator
{
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef T* pointer;
typedef T& reference;
};
//为避免写代码时挂一漏万,自行开发的迭代器最好继承自下面这个 std::iterator
template<class Category,class T,class Distance=ptrdiff_t,class Pointer=T*,class Reference=T&>
struct iterator
{
typedef Category iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef Pointer pointer;
typedef Reference reference;
}
//"榨汁机"traits
template<class Iterator>
struct iterator_traits
{
typedef typename Iterator::iterator_category iterator_category;
typedef typename Iterator::value_type value_type;
typedef typename Iterator::difference_type difference_type;
typedef typename Iterator::pointer pointer;
typedef typename Iterator::reference reference;
}
//针对原生指针(naive pointer)而设计的traits偏特性化版本
template<class T>
struct iterator_traits
{
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef T& reference;
};
//针对Pointer-to-const而设计的traits偏特化版本
template<class T>
struct iterator_traits<const T*>
{
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef const T* pointer;
typedef const T reference;
};
//判断某iterator的类型
template<class Iterator>
inline typename iterator_traits::iterator_category
iterator_category(const Iterator& It)
{
typedef typename iterator_traits::iterator_category
return category();
}
//获取迭代器的value_type
template<class Iterator>
inline typename iterator_traits::value_type*
value_type(const Iterator& It)
{
return static_cast<typename iterator_traits::value_type*>(0);
}
//获取迭代器的distance_type
template<class Iterator>
inline typename iterator_traits::difference_type*
distance_type(const Iterator& It)
{
return static_cast<typename iterator_traits::difference_type*>(0);
}
//....................................................................
/*函数重载,使迭代器能在编译时期就确定调用哪个函数*/
template <class _InputIter, class _Distance>
/*迭代器类型为input_iterator_tag的函数定义*/
inline void __advance(_InputIter& __i, _Distance __n, input_iterator_tag) {
while (__n--) ++__i;
}
template <class _BidirectionalIterator, class _Distance>
/*迭代器类型为bidirectional_iterator_tag的函数定义*/
inline void __advance(_BidirectionalIterator& __i, _Distance __n,
bidirectional_iterator_tag) {
__STL_REQUIRES(_BidirectionalIterator, _BidirectionalIterator);
if (__n >= 0)
while (__n--) ++__i;
else
while (__n++) --__i;
}
template <class _RandomAccessIterator, class _Distance>
/*迭代器类型为random_access_iterator_tag的函数定义*/
inline void __advance(_RandomAccessIterator& __i, _Distance __n,
random_access_iterator_tag) {
__STL_REQUIRES(_RandomAccessIterator, _RandomAccessIterator);
__i += __n;
}
template <class _InputIterator, class _Distance>
/*决定调用哪个函数,这是一个对外接口*/
inline void advance(_InputIterator& __i, _Distance __n) {
__STL_REQUIRES(_InputIterator, _InputIterator);
__advance(__i, __n, iterator_category(__i));
}
//....................................................................
template<class InputIterator>
inline typename std::iterator_traits::difference_type distance(InputIterator first, InputIterator last){
return __distance(first, last, std::iterator_traits::iterator_category());
}
template<class InputIterator>
inline typename std::iterator_traits::difference_type= 0;
while (first != last){
++first; ++n;
}
return n;
}
template<class InputIterator>
inline typename std::iterator_traits::difference_type \
__distance(InputIterator first, InputIterator last, std::random_access_iterator_tag){
return last - first;
}
//....................................................................
}
#endif
typetraits.h
#ifdef _TYPE_TRAITS_H_
#define _TYPE_TRAITS_H_
namespace EasySTL
{
struct _true_type{};
struct _false_type{};
/*
*萃取传入的T类型的类型特征
*/
template
struct _type_traits
{
typedef _false_type has_trivial_default_constructor;
typedef _false_type has_trivial_copy_constructor;
typedef _false_type has_trivial_assignment_operator;
typedef _false_type has_trivial_destructor;
typedef _false_type has_POD_type;
};
template<>
struct _type_traits
{
typedef _true_type has_trivial_default_constructor;
typedef _true_type has_trivial_copy_constructor;
typedef _true_type has_trivial_assignment_operator;
typedef _true_type has_trivial_destructor;
typedef _true_type has_POD_type;
};
template<>
struct _type_traits
{
typedef _true_type has_trivial_default_constructor;
typedef _true_type has_trivial_copy_constructor;
typedef _true_type has_trivial_assignment_operator;
typedef _true_type has_trivial_destructor;
typedef _true_type has_POD_type;
};
template<>
struct _type_traits
{
typedef _true_type has_trivial_default_constructor;
typedef _true_type has_trivial_copy_constructor;
typedef _true_type has_trivial_assignment_operator;
typedef _true_type has_trivial_destructor;
typedef _true_type has_POD_type;
};
template<>
struct _type_traits
{
typedef _true_type has_trivial_default_constructor;
typedef _true_type has_trivial_copy_constructor;
typedef _true_type has_trivial_assignment_operator;
typedef _true_type has_trivial_destructor;
typedef _true_type has_POD_type;
};
template<>
struct _type_traits
{
typedef _true_type has_trivial_default_constructor;
typedef _true_type has_trivial_copy_constructor;
typedef _true_type has_trivial_assignment_operator;
typedef _true_type has_trivial_destructor;
typedef _true_type has_POD_type;
};
template<>
struct _type_traits
{
typedef _true_type has_trivial_default_constructor;
typedef _true_type has_trivial_copy_constructor;
typedef _true_type has_trivial_assignment_operator;
typedef _true_type has_trivial_destructor;
typedef _true_type has_POD_type;
};
template<>
struct _type_traits
{
typedef _true_type has_trivial_default_constructor;
typedef _true_type has_trivial_copy_constructor;
typedef _true_type has_trivial_assignment_operator;
typedef _true_type has_trivial_destructor;
typedef _true_type has_POD_type;
};
template<>
struct _type_traits
{
typedef _true_type has_trivial_default_constructor;
typedef _true_type has_trivial_copy_constructor;
typedef _true_type has_trivial_assignment_operator;
typedef _true_type has_trivial_destructor;
typedef _true_type has_POD_type;
};
template<>
struct _type_traits }
{ #endif
typedef _true_type has_trivial_default_constructor;
typedef _true_type has_trivial_copy_constructor;
typedef _true_type has_trivial_assignment_operator;
typedef _true_type has_trivial_destructor;
typedef _true_type has_POD_type;
};
template<>
struct _type_traits
{
typedef _true_type has_trivial_default_constructor;
typedef _true_type has_trivial_copy_constructor;
typedef _true_type has_trivial_assignment_operator;
typedef _true_type has_trivial_destructor;
typedef _true_type has_POD_type;
};
template<>
struct _type_traits
{
typedef _true_type has_trivial_default_constructor;
typedef _true_type has_trivial_copy_constructor;
typedef _true_type has_trivial_assignment_operator;
typedef _true_type has_trivial_destructor;
typedef _true_type has_POD_type;
};
template<>
struct _type_traits
{
typedef _true_type has_trivial_default_constructor;
typedef _true_type has_trivial_copy_constructor;
typedef _true_type has_trivial_assignment_operator;
typedef _true_type has_trivial_destructor;
typedef _true_type has_POD_type;
};
template<>
struct _type_traits
{
typedef _true_type has_trivial_default_constructor;
typedef _true_type has_trivial_copy_constructor;
typedef _true_type has_trivial_assignment_operator;
typedef _true_type has_trivial_destructor;
typedef _true_type has_POD_type;
};
template<>
struct _type_traits
{
typedef _true_type has_trivial_default_constructor;
typedef _true_type has_trivial_copy_constructor;
typedef _true_type has_trivial_assignment_operator;
typedef _true_type has_trivial_destructor;
typedef _true_type has_POD_type;
};
template<>
struct _type_traits
{
typedef _true_type has_trivial_default_constructor;
typedef _true_type has_trivial_copy_constructor;
typedef _true_type has_trivial_assignment_operator;
typedef _true_type has_trivial_destructor;
typedef _true_type has_POD_type;
};
template<>
struct _type_traits
{
typedef _true_type has_trivial_default_constructor;
typedef _true_type has_trivial_copy_constructor;
typedef _true_type has_trivial_assignment_operator;
typedef _true_type has_trivial_destructor;
typedef _true_type has_POD_type;
};
//指针是PDD类型
template
struct _type_traits
{
typedef _true_type has_trivial_default_constructor;
typedef _true_type has_trivial_copy_constructor;
typedef _true_type has_trivial_assignment_operator;
typedef _true_type has_trivial_destructor;
typedef _true_type has_POD_type;
};
template
struct _type_traits
{
typedef _true_type has_trivial_default_constructor;
typedef _true_type has_trivial_copy_constructor;
typedef _true_type has_trivial_assignment_operator;
typedef _true_type has_trivial_destructor;
typedef _true_type has_POD_type;
};
template<>
struct _type_traits
{
typedef _true_type has_trivial_default_constructor;
typedef _true_type has_trivial_copy_constructor;
typedef _true_type has_trivial_assignment_operator;
typedef _true_type has_trivial_destructor;
typedef _true_type has_POD_type;
};
template<>
struct _type_traits
{
typedef _true_type has_trivial_default_constructor;
typedef _true_type has_trivial_copy_constructor;
typedef _true_type has_trivial_assignment_operator;
typedef _true_type has_trivial_destructor;
typedef _true_type has_POD_type;
};
template<>
struct _type_traits
{
typedef _true_type has_trivial_default_constructor;
typedef _true_type has_trivial_copy_constructor;
typedef _true_type has_trivial_assignment_operator;
typedef _true_type has_trivial_destructor;
typedef _true_type has_POD_type;
};
template<>
struct _type_traits
{
typedef _true_type has_trivial_default_constructor;
typedef _true_type has_trivial_copy_constructor;
typedef _true_type has_trivial_assignment_operator;
typedef _true_type has_trivial_destructor;
typedef _true_type has_POD_type;
};
template<>
struct _type_traits
{
typedef _true_type has_trivial_default_constructor;
typedef _true_type has_trivial_copy_constructor;
typedef _true_type has_trivial_assignment_operator;
typedef _true_type has_trivial_destructor;
typedef _true_type has_POD_type;
};
template<>
struct _type_traits
{
typedef _true_type has_trivial_default_constructor;
typedef _true_type has_trivial_copy_constructor;
typedef _true_type has_trivial_assignment_operator;
typedef _true_type has_trivial_destructor;
typedef _true_type has_POD_type;
};
}
#endif
End