C++ 迭代器的類型

C++ 迭代器的類型

C++ 對於常用的數據結構進行了封裝,例如:

  1. 數組 : vector, array, string.
  2. 鏈表 : list, forward_list.
  3. 棧 : stack.
  4. 隊列 : deque, queue.
  5. 樹 : set, map, multimap, multiset
  6. 哈希表: unorder_set, unorder_map, unorder_multiset, unorder_multimap.

數據結構的封裝常常是爲了給使用者提供更加方便的操作;上面的數據結構以及非常的多了,如果我們需要操作其中保存在數據結構中的成員應該怎麼辦呢?STL爲了給使用者提供方便,讓使用者在不瞭解任何的底層實現的時候,也能使用這個數據結構成員,給每個容器結構設計了一個迭代器iterator, 使用者通過iterator遍歷訪問或者操作容器中的數據,而不需要掌握數據結構(例如二叉樹需要中序遍歷等等)。

C++除了提供容器之外,還對容器提供了相關的算法,例如:

void advance(_InIt& _Where, _Diff _Off)

代表迭代器前移多少個。

爲了使得算法能夠更好的使用迭代器,STL對迭代器提供了分類,每種不同類型的迭代器使用不同的算法實現細節來完成。

1. 迭代器類型的定義

我們以vector中的迭代器爲例:

template<class _Myvec>
	class _Vector_iterator
		: public _Vector_const_iterator<_Myvec>
	{	// iterator for mutable vector
public:
	using _Mybase = _Vector_const_iterator<_Myvec>;
	using iterator_category = random_access_iterator_tag;

	using value_type = typename _Myvec::value_type;
	using difference_type = typename _Myvec::difference_type;
	using pointer = typename _Myvec::pointer;
	using reference = value_type&;
    };

vector的迭代器,定義了一個迭代器的類型using iterator_category = random_access_iterator_tag;,代表這個迭代器可以隨機的訪問(+,-, 偏移等操作)。

STL整個的迭代器類型如下:

struct input_iterator_tag
	{	// identifying tag for input iterators
	};

struct output_iterator_tag
	{	// identifying tag for output iterators
	};

struct forward_iterator_tag
	: input_iterator_tag
	{	// identifying tag for forward iterators
	};

struct bidirectional_iterator_tag
	: forward_iterator_tag
	{	// identifying tag for bidirectional iterators
	};

struct random_access_iterator_tag
	: bidirectional_iterator_tag
	{	// identifying tag for random-access iterators
	};

從上我們發現迭代器分爲輸入、輸出、正向、雙向、隨機訪問五種。

每種類型的迭代器使用用一個xxxx_iterator_tag變量類型來定義。

2. 迭代器類型的使用

我們看下C++的迭代器怎麼使用的,這裏使用最簡單的算法advance爲例:

template<class _InIt,
	class _Diff>
	_CONSTEXPR17 void _Advance1(_InIt& _Where, _Diff _Off, input_iterator_tag)
	{	// increment iterator by offset, input iterators
	_STL_ASSERT(_Off >= 0, "negative advance of non-bidirectional iterator");
	for (; 0 < _Off; --_Off)
		{
		++_Where;
		}
	}

template<class _BidIt,
	class _Diff>
	_CONSTEXPR17 void _Advance1(_BidIt& _Where, _Diff _Off, bidirectional_iterator_tag)
	{	// increment iterator by offset, bidirectional iterators
	for (; 0 < _Off; --_Off)
		{
		++_Where;
		}

	// the following warning is triggered if _Diff is unsigned
#pragma warning(suppress: 6294)	// Ill-defined for-loop: initial condition does not satisfy test.
								// Loop body not executed.
	for (; _Off < 0; ++_Off)
		{
		--_Where;
		}
	}

template<class _RanIt,
	class _Diff>
	_CONSTEXPR17 void _Advance1(_RanIt& _Where, _Diff _Off, random_access_iterator_tag)
	{	// increment iterator by offset, random-access iterators
	_Where += _Off;
	}

template<class _InIt,
	class _Diff>
	_CONSTEXPR17 void advance(_InIt& _Where, _Diff _Off)
	{	// increment iterator by offset, arbitrary iterators
		// we remove_const_t before _Iter_cat_t for better diagnostics if the user passes an iterator that is const
	_Advance1(_Where, _Off, _Iter_cat_t<remove_const_t<_InIt>>());
	}

這裏分別對不同類型的迭代器做實現:

  1. void _Advance1(_InIt& _Where, _Diff _Off, input_iterator_tag) : 代表正向的迭代器。
  2. void _Advance1(_BidIt& _Where, _Diff _Off, bidirectional_iterator_tag) : 雙向的迭代器:
  3. void _Advance1(_RanIt& _Where, _Diff _Off, random_access_iterator_tag) : 隨機訪問的迭代器。

也就是說算法針對不同類型的迭代器,實現了不同的算法細節。

那麼C++怎麼知道一個迭代器屬於那種類型呢?這個就跟_Iter_cat_t<remove_const_t<_InIt>>()這個操作有關了,這個操作的代碼如下:

template<class _Iter>
	using _Iter_cat_t = typename iterator_traits<_Iter>::iterator_category;

也就是說是使用萃取機的iterator_traits<_Iter>::iterator_category;來提取迭代器的iterator_category,然後使用iterator_category來創建一個臨時對象來匹配函數。

3. 總結

STL的算法針對迭代器進行操作,爲了算法的高效,需要對不同的迭代器使用不同的算法實現,因此每個迭代器都定義了一個iterator_category來表示迭代器的類型。算法在運行的時候,就會根據iterator_category不同,來選擇具體的算法細節。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章