STL原始碼分析之迭代器
前言
迭代器是將演算法和容器兩個獨立的泛型進行調和的一個介面. 使我們不需要關係中間的轉化是怎麼樣的就都能直接使用迭代器進行資料訪問. 而迭代器最重要的就是對operator *
和operator->
進行過載, 使它表現的像一個指標.
型別
迭代器根據移動特性和實施操作被分為5類
- input iterator(輸入迭代器) : 迭代器所指的內容不能被修改,只讀且只能執行一次讀操作.
- output iterator(輸出迭代器) : 只寫並且一次只能執行一次寫操作.
- forward iterator(正向迭代器) : 支援讀寫操作且支援多次讀寫操作.
- bidirectional iterator(雙向迭代器) : 支援雙向的移動且支援多次讀寫操作.
- 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
是用於計算連個迭代器之間的距離, 因為過載就可以通過不同的迭代器型別選擇不同的函式來提高效率.
這裡distance
的iterator_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 Tvalue_type; typedef Distancedifference_type; typedef T*pointer; typedef T&reference; }; struct output_iterator { typedef output_iterator_tag iterator_category; typedef voidvalue_type; typedef voiddifference_type; typedef voidpointer; typedef voidreference; }; template <class T, class Distance> struct forward_iterator { typedef forward_iterator_tag iterator_category; typedef Tvalue_type; typedef Distancedifference_type; typedef T*pointer; typedef T&reference; }; template <class T, class Distance> struct bidirectional_iterator { typedef bidirectional_iterator_tag iterator_category; typedef Tvalue_type; typedef Distancedifference_type; typedef T*pointer; typedef T&reference; }; template <class T, class Distance> struct random_access_iterator { typedef random_access_iterator_tag iterator_category; typedef Tvalue_type; typedef Distancedifference_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
萃取器做準備. 下篇進行探討.