当前位置:   article > 正文

STL源码剖析-迭代器概念与traits编程技法_迭代器与traits编程

迭代器与traits编程

1.迭代器模式:提供一种方法,使之能够依序寻访某个容器所包含的各个元素,而又无需暴露该聚合物的内部表达式。

2.STL中心思想:将数据容器和算法分开,彼此独立设计,最后应迭代器将它们撮合在一起。

3.迭代器是一种只能指针,最重要的编程工作就是对operator*和operator->进行重载工作。

4.迭代器例子:

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

    template<typename T>  
    struct ListItem{  //链表节点数据结构  
        ListItem() :m_next(nullptr){}//默认构造函数  
        ListItem(T value, ListItem* p = nullptr) { m_value = value; m_next = p; } //构造函数  
        ListItem* Next() const { return m_next; }  //返回m_next指针  
        T Value() const { return m_value; } //返回值  
        T m_value;  //存储的数据  
        ListItem* m_next; //指向下一个ListItem的指针  
    };  

    template<typename T>  
    class List{ //链表数据结构  
    public:  
        List() :m_begin(nullptr), m_befend(nullptr), m_end(nullptr){} //默认构造函数  
        void Push_back(T value){  //从链表尾部插入元素  
            ListItem<T>* temp = new ListItem<T>(value, nullptr);  
            if (m_begin == nullptr){  
                m_begin = m_befend = temp;  
            }  
            else{  
                m_befend->m_next = temp;  
                m_befend = temp;  
            }  
        }  
        void Push_front(T value){  //从链表头部插入元素  
            ListItem<T>* temp = new ListItem<T>(value);  
            if (m_begin == nullptr){  
                m_begin = m_befend = temp;  
            }  
            else{  
                temp->m_next = m_begin;  
                m_begin = temp;  
            }  

        }  
        ListItem<T>* Begin() const { return m_begin; }  //返回链表头部指针  
        ListItem<T>* End() const { return m_end; }      //返回链表尾部指针  
        void Print(ostream& os = cout) const{        //打印链表元素  
            for (ListItem<T>* p = Begin(); p != End(); p = p->Next())  
                os << p->Value() << " ";  
            os << endl;  
        }  
    private:  
        ListItem<T>* m_begin; //指向List头部的指针  
        ListItem<T>* m_befend; //指向List最后一个元素的指针  
        ListItem<T>* m_end; //指向List尾部的指针  
        long m_size; //List的长度  
    };  
    // ListIter继承STL提供的iterator,保证符合STL所需之规范  
    template<typename T>  
    class ListIter :public iterator<forward_iterator_tag, T>{  
    public:  
        ListIter(T* p = nullptr) :m_ptr(p){}   //默认构造函数  
        T& operator*() const { return *m_ptr; }; //dereference,解引用  
        T* operator->() const { return m_ptr; } //member access,成员访问  
        ListIter& operator++(){ m_ptr = m_ptr->Next(); return *this; } //前置++操作,暴露了ListItem的Next()  
        ListIter operator++(int){ ListIter temp = *this; ++*this; return temp; }//后置++操作  
        bool operator==(const ListIter& i)const{ return m_ptr == i.m_ptr; }//判断两个ListIter是否指向相同的地址  
        bool operator!=(const ListIter& i)const{ return m_ptr != i.m_ptr; }//判断两个ListIter是否指向不同的地址  
    private:  
        T* m_ptr;  //保持与容器之间的一个联系  
    };  

    template<typename T>  //本例中value的型别是int,iter的型别是ListItem<int>,必须写operator==重载函数  
    bool operator==(const ListItem<T>& item, const T& n){  
        return item.Value() == n;  
    }  

    //template<typename T>  //STL源码剖析中说是要写operator!=重载函数,但是我这边不成功,需要写的是operator==重载函数  
    //bool operator!=(const ListItem<T>& item, const T& n){  
    //  return item.Value() != n;  
    //}  

    int main(){  
        List<int> mylist;  
        for (int i = 0; i < 5; ++i){  
            mylist.Push_front(i);  
            mylist.Push_back(i + 2);  
        }  
        mylist.Print();  

        ListIter<ListItem<int>> begin(mylist.Begin()); //暴露了ListItem  
        ListIter<ListItem<int>> end(mylist.End()); //暴露了ListItem  
        ListIter<ListItem<int>> iter;  

        iter = find(begin, end, 1);//从链表中查找3  
        if (iter == end)  
            cout << "not found" << endl;  
        else  
            cout << "found" << endl;     //输出found  

        iter = find(begin, end, 7);//从链表中查找3  
        if (iter == end)  
            cout << "not found" << endl;  //输出not found  
        else  
            cout << "found" << endl;  

        system("pause");  
        return 0;  
    }  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104

上面的例子在main函数中暴露了ListIter暴露了ListItem的Next()。如果不是为了迭代器,ListItem应该藏起来,所以把迭代器的开发工作交给List的设计者,这样实现细节就得以封装不被使用者看到,这也是每一种容器有专属迭代器的原因。

迭代器分为五类:

Input Iterator: 这种迭代器所指的对象,不允许外界改变。只读(read only)

Output Iterator: 只写(write only)。

Forward Iterator: 在此种迭代器所形成的区间上进行读写操作。

Bidirectional Iterator: 可双向移动。

RandomAccess Iterator: 前四种迭代器都只提供一部分指针算术能力(前三种支持operator++,第四种再加上operator–),第五种则涵盖所有指针算数能力,包括p+n,p-n,p[n],p1-p2,p1

    template<class I>  
    struct iterator_traits{  
        typedef typename I::value_type  value_type;  
    };  
  • 1
  • 2
  • 3
  • 4

这个所谓的traits的意义是如果I定义有自己的value_type,那么通过这个traits的作用,萃取出来的value_type就是I::value_type。

    template<class I>  
    struct iterator_traits<I*>{  
        typedef I value_type; //偏特化版——迭代器是原生指针  
    };  
    template<class I>  
    struct iterator_traits<const I*>{  
    typedef I value_type; //偏特化版——迭代器是pointer-to-const时,萃取出来的型别是I而非const I  
    };  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这里写图片描述

    template<class I>  
    struct iterator_traits{  
        typedef typename I::iterator_category  iterator_category;  
        typedef typename I::value_type  value_type;  
        typedef typename I::difference_type difference_type;  
        typedef typename I::pointer pointer;  
        typedef typename I::reference reference;  
    };  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

7.迭代器的相应类别:

1)value_type: value_type是指迭代器所指对象的类型.

2)difference_type: different_type用来表示两个迭代器之间的距离.

3)reference_type: reference_type是指迭代器所指对象的类型的引用.

4)pointer_type: pointer_type是指迭代器所指对象的指针.

5)iterator_category: iterator_category是指迭代器的类型.共有5种迭代器类型.

//五个用作标记用的型别

    struct input_iterator_tag{};  
    struct output_iterator_tag{};  
    struct forward_iterator_tag:public input_iterator_tag{};  
    struct bidirectional_iterator_tag :forward_iterator_tag{};  
    struct random_access_iterator_tag : public bidirectional_iteratir_tag{};  
  • 1
  • 2
  • 3
  • 4
  • 5

8.STL提供一个iterator类,每个新设计的迭代器都继承自它,这样就能保证这些自定义的迭代器符合STL所需的规范,iterator类具体定义如下:

template<typename Category,  
         typename T,  
         typename Distance = ptrdiff_t,  
         typename Pointer = T*,  
         typename Reference = T&>  
struct iterator  
{  
    typedef Category iterator_category;  
    typedef T value_type;  
    typedef Distance difference_type;  
    typedef Pointer pointer;  
    typedef Reference reference;  
}; 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

traits编程技法大量运用于STL实现中,它利用"内嵌类型"的编程技巧与编译器的参数推导功能,增强了c++未能提供的关于型别认证方面的能力.

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/589661
推荐阅读
相关标签
  

闽ICP备14008679号