《STL源码剖析》迭代器(iterators)学习笔记

迭代器(iterators)

iterator模式定义如下:提供一种方法,使之能够依序寻访某个容器所含的各个元素,有无需暴露该容器的内部表述方式。

1. 迭代器的自增

​ 以 List 为例,迭代器重载了自增运算符来实现指针的右移,以下为前置及后置递增的实现方法:

// 前置自增,因为返回的是右移之后的结果,所以要返回一个引用。
ListIter& operator++(){
	ptr = ptr->next();
	return *this;
}
// 后置递增,返回的是当前的指针,这个tmp用完就释放了,不用返回引用。
ListIter operator++(int){
    ListIter tmp = *this;
    ++*this;
    return tmp;
}

2. Traits编程技法

​ 在迭代器的使用过程中,常常会用到迭代(比如所指对象)的型别,但是CPP并没有typeof()的操作,所以需要一些其他的方式,解决办法如下:

  1. 首先是利用模板函数的参数推导机制:

    template <class I, class T>
    void func_impl(I iter, T t){
    T tmp;	// 这里就获得了类型 T
    // .....
    }
    
  2. 但如果这个value type适用于函数的传回值,那就没辙了。因为template只能用于推导参数型别,而无法用于推导函数返回值型别。因此然后尝试使用声明内嵌型别:

    template <class T>
    struct MyIter{
    	typedef T value_type;
    	T* ptr;
    	MyIter(T* p=0):ptr(p){}
        T& operator*() const{return *ptr;}
        // .... 
    }
    template <class I>
    typename I::value_type  // 返回值型别
    func(I ite){
        return *ite;
    }
    // ...
    MyIter<int> ite(new int(8));
    cout<< func(ite);		// 8
    

    但是这也有一个问题,那就是并不是所有的迭代器都不是class type,比如原生指针,这样就无法为其定义内嵌类型。

  3. 模板偏特化

    ​ 模板偏特化是针对template更进一步的条件限制设计出的特化版本。可以针对不是class type的迭代器,为其创建一些之,来取出正确的(希望的)value type。最常用的迭代器相应型别有五种: value type,difference type,pointer, reference, iterator catagoly。对于所有的迭代器,都要定义这五种型别,然后traits就可以从中取出相应的值。

    • value type,即迭代器所指对象的型别
    • difference type,表示两个迭代器之间的距离,因此它也可以用来表示一个容器的最大容量。
    • reference,一个迭代器解引用(*p)后的型别,没被用过
    • pointer,指向迭代器所指的对象,没被用过
    • iterator_categoly,迭代器被分为五类:Input IteratorOutput IteratorForward IteratorBidirectional IteratorRandom Access Iterator,前三种支持operator++,第四种支持operator--,第五种则包含所有算术能力:双向、跳跃等。这五种迭代器的阶级依次递增。
    • 对于任何一个迭代器,其类型永远应该落在“该迭代器所隶属之各种类型中,最强化的那个”。例如,int*既是Random Access Iterator,又是Bidirectional lterator,同时也是 Forward lterator,而且也是Input lterator,那么,其类型应该归属为random_access_iterator_tag
    • 而算法在接受一个迭代器类型的时候,以能接受的最低阶迭代器类型命名。
    • 设计适当的相应型别( associated types),是迭代器的责任。设计适当的迭代器,则 是容器的责任。唯容器本身,才知道该设计出怎样的迭代器来遍历自己,并执行迭代器该有的各种行为(前进、后退、取值、取用成员…)。

3. 针对不同迭代器的 traits

template <class Iterator>struct iterator_traits {
    typedef typename Iterator::iterator_category    iterator_category ;
    typedef typename Iterator::valuetype            value_type;
    typedef typename Iterator::difference_type      difference_type;
    typedef typename Iterator::pointer              pointer;
    typedef typename Iterator::reference            reference;
};
//针对原生指针(native pointer)而设计的 traits 偏特化版
template <class T>
struct iterator_traits<T*>{
    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 constT*                     pointer;
    typedef const T&                    reference;
};

4. __type_traits

traits编程技法很棒,适度弥补了C++语言本身的不足。STL只对迭代器加以规范,制定出iterator_traits 这样的东西。SGI 把这种技法进一步扩大到迭代器以外的世界,于是有了所谓的__type_traits。双底线前缀词意指这是SGISTL内部所用的东西,不在STL标准规范之内。
iterator_traits负责萃取迭代器的特性,__type_traits则负责萃取型别的特性。此处我们所关注的型别特性是指:这个型别是否具备non-trivial defalt ctor?是否具备non-trivial copy ctor?是否具备non-trivial assignment operator?是否具备non-trivial dtor?如果答案是否定的,我们在对这个型别进行构造、析构、拷贝、赋值等操作时,就可以采用最有效率的措施(例如根本不调用身居高位,不谋实事的那些constructor,destructor),而采用内存直接处理操作如malloc()、memcpy ()等等,获得最高效率。这对于大规模而操作频繁的容器,有着显著的效率提升。

​ 程序可以利用如下代码来回带上面的问题:

__type_traits<T>::has_trivial_default_constructor
__type_traits<T>::has_trivial_copy_constructor
__type_traits<T>::has_trivial_assignment_operator
__type_traits<T>::has_trivial_destruct
__type_traits<T>::is_POD_type

​ 而上述式子则传回如下的东西进行回复:

struct __true_type {};
struct __false_type {};

这两个空白 classes没有任何成员,不会带来额外负担,却又能够标示真假,满足我们所需。

​ SGI 默认把所有内嵌性别都定义为__false_type,然后针对每一个标量型别设计适当的__false_type特化版本。具体见第106页。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值