1. 程式人生 > >STL源碼分析之叠代器

STL源碼分析之叠代器

移動 cpp 源碼 向上 只讀 traits opera 需要 存在

前言

叠代器是將算法和容器兩個獨立的泛型進行調和的一個接口. 使我們不需要關系中間的轉化是怎麽樣的就都能直接使用叠代器進行數據訪問. 而叠代器最重要的就是對operator *operator->進行重載, 使它表現的像一個指針.

類型

叠代器根據移動特性和實施操作被分為5類

  1. input iterator(輸入叠代器) : 叠代器所指的內容不能被修改, 只讀且只能執行一次讀操作.
  2. output iterator(輸出叠代器) : 只寫並且一次只能執行一次寫操作.
  3. forward iterator(正向叠代器) : 支持讀寫操作且支持多次讀寫操作.
  4. bidirectional iterator(雙向叠代器) : 支持雙向的移動且支持多次讀寫操作.
  5. random access iterator(隨即訪問叠代器) : 支持雙向移動且支持多次讀寫操作. p+n, p-n等.

1~4類叠代器執行操作的就如 : p++, ++p, p->而不是5類的p+n操作. 不明白的我們下面會進行講解.

源碼分析

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

這五個類都是空類, 只是為了之後調用時通過類選擇不同的重載函數. 繼承是為了可以使用傳遞調用,當不存在某種叠代器類型匹配時編譯器會依據繼承層次向上查找進行傳遞, 就可以通過繼承關系來決定選擇最優的調用. 我們通過用distance來講最優.

distance是用於計算連個叠代器之間的距離, 因為重載就可以通過不同的叠代器類型選擇不同的函數來提高效率.

這裏distanceiterator_category函數是每個叠代器自己定義的, 跟traits萃取器相關我準備放在下一篇章講解. 這裏只要知道它能通過first參數推斷出是哪一類的叠代器從而選擇調用哪一個函數.

template <class InputIterator, class Distance>
inline void distance(InputIterator first, InputIterator last, Distance& n) 
{
    __distance(first, last, n, iterator_category(first));
}
    
template <class InputIterator, class Distance>
inline void __distance(InputIterator first, InputIterator last, Distance& n, 
                       input_iterator_tag) 
{
    while (first != last) 
    { ++first; ++n; }
}

template <class RandomAccessIterator, class Distance>
inline void __distance(RandomAccessIterator first, RandomAccessIterator last, 
                       Distance& n, random_access_iterator_tag) 
{
    n += last - first;
}

distance源碼可以看出來不同的叠代器的計算方式並不一樣, random_access_iterator_tag的距離的計算效率最高, 其他都是通過++操作來依次訪問. 當然random_access_iterator_tag類的叠代器也是可以調用input_iterator_tag, 但是顯然效率很低, 所以不同的叠代器最自己最佳的效率. 通過iterator_category進行最優選擇.

五類叠代器源碼

五類叠代器的結構體, 可以看出來每個類都定義了相同的變量名. 但是每個名的類型不一定一樣, 提供統一的名是為了traits進行類型萃取. 每個類的iterator_category都是代表了不同的叠代器, 通過它來選擇該叠代器執行的函數.

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

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

iterator_category判斷傳入叠代器的類型

template <class Iterator>
inline typename iterator_traits<Iterator>::iterator_category
iterator_category(const Iterator&) {
  typedef typename iterator_traits<Iterator>::iterator_category category;
  return category();
}

總結

這一篇僅僅只是講解了一些關於叠代器類型, 和一點traits的一點用法. 關於每個叠代器都設置為相同的類型名都是為了traits萃取器做準備. 下篇進行探討.

STL源碼分析之叠代器