模板編程-迭代器

迭代器ios

迭代器源於指針而高於指針,併成爲分割容器與算法的一條界河.在一個共同的迭代器界面約定之下,不一樣的算法與不一樣的容器只要其迭代器要求一致就能夠相互組合.c++

 

迭代器分類算法

c++標準庫中對迭代器進行了詳細的分類,迭代器按其所能提供的操做,能夠分爲五種類型,分別爲:dom

    輸入迭代器(input iterator) > 前向迭代器(forward iterator) > 雙向迭代器(bidirectional iterator) > 跳轉迭代器(random access iterator)以及輸出迭代器(output iterator).
函數

後者是前者的子集.輸入迭代器提供的操做最少,只支持當前位置數據及前進一位。而跳轉迭代器的功能最爲豐富,不只支持取數據,還能夠前進或者後退多位。輸出迭代器支持向所指位置寫入數據。this

 

1.輸入迭代器與前向迭代器的區別.spa

前向迭代器與輸入迭代器的要求極爲類似,除去構造函數及比較操做外,兩者都提供自加1操做前移一位以及去引用取值.而最關鍵的區別在於,前向迭代器可以保證兩個迭代器實例a與b,若是a==b,則必定也知足++a=++b,而輸入迭代器不能保證這一點.指針

例子:code

 1 #include <iostream>
 2 #include <stack>
 3 
 4 template<typename Stack>
 5 class stack_iterator{
 6 public:
 7      typedef typename Stack::value_type value_type;
 8      typedef typename Stack::reference reference;
 9          
10 private:
11       Stack &s;
12       value_type *pos;
13 public:
14       stack_iterator(Stack &_s):s(_s),pos(_s.size()?_s.top():0){}
15       reference operator *() const{return *pos;}
16       stack_iterator& operator++ (){
17           s.pop();
18           pos=s.size()?&s.top():0;
19           return *this;
20       }
21       
22       bool operator ==(stack_iterator const& rhs) const {return pos==rhs.pos;}
23       bool operator !=(stack_iterator const& rhs) const {return pos!=rhs.pos;}
24 };
25 
26 int main(){
27     using namespace std;
28     int numbers[]={0,1,2,3,4};
29     typedef stack<int> int_stack;
30     int_stack s;
31     
32     for(int i=0;i<5;i++) s.push(numbers[i]);
33     
34     stack_iterator<int_stack> a(s);
35     stack_iterator<int_stack> b(s);
36     
37     cout<<((a==b)?"a"==b"?"a!=b")<<endl;
38     ++a;++b;
39     cout<<((a==b)?"++a==++b":"++a!=++b")<<endl;
40     
41     coout<<*a<<endl;//危險操做,a所指數據已經出棧,空間已被釋放
42 }

 

從中咱們能夠體會到對輸入迭代器的自加1操做的意義.一旦某迭代器經過自加1操做前移一位後,則全部指向以前的迭代器不能保證仍然有效,因此迭代器的前移不是破壞了容器中的數據至少也是屏蔽了以前的數據.而基於前向迭代器的算法則不一樣,雖然前向迭代器只能前移,可是能夠保證a==b能夠得出++a==++b,故能夠經過保存迭代器的多個副原本實現屢次遍歷.blog

 

以標準庫中容器所提供的迭代器爲例。vector、deque及array都能提供可寫跳轉迭代器。list能提供可寫雙向迭代器。forward_list能提供可寫前向迭代器。set和multiset能提供只讀雙向迭代器。map和multimap能提供只讀雙向迭代器.

 

二:迭代器屬性類模板

迭代器除了要提供必要的操做外,還應該包含足夠的信息以描述其自身的屬性,如所屬迭代器類型、所指數據等.通常而言,相關屬性都是經過在迭代器類型中嵌套定義類型來定實現的.所以,在標準中特別定義了一個模板類std::iterator_traits<T>爲算法提取迭代器各類屬性之用.

標準中爲迭代器規定了五個屬性:

  • difference_type (迭代器差值類型)
  • value_type(迭代器所指數據類型)
  • pointer(數據指針類型)
  • reference(數據引用類型)
  • iterator_category(迭代器所屬類型)

 

iterator_category標記了迭代器所屬類型.標準中爲區分迭代器類型,特地定義了以下的五種標籤.

  •   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 {};

所謂標籤,即一個空結構體,純爲標記類型所用.

利用iterator_category,做者能夠根據迭代器類型採起不一樣的策略.

 1 //適用於前向迭代器的advance函數實現,n次加1操做
 2 template <typename I>
 3 void advance_impl(I &i,typename std::iterator_traits<I>::difference_type n,
 4                                     std::forward_iterator_tag){
 5         for(;n>0;n--) i++;
 6 }
 7 
 8 //適用於跳轉迭代器的advance函數實現,直接用i+=n
 9 template <typename I>
10 void advance_impl(I &i,typename std::iterator_traits<I>::difference_type n,
11                                      std::random_access_iterator_tag){
12      i+=n;                                         
13 }
14 
15 template <typename I>
16 void advance(I &i,typename I::difference_type n){
17        //以iterator_category()爲啞參數指導編譯器選擇適當的重載實現
18        advance_impl(i,n,typename std::iterator_traits<I>::iterator_category());
19 }
相關文章
相關標籤/搜索