溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

迭代器——STL關(guān)鍵所在

發(fā)布時(shí)間:2020-07-07 10:28:05 來源:網(wǎng)絡(luò) 閱讀:333 作者:檸公子 欄目:編程語言

迭代器基本介紹:

STL的設(shè)計(jì)中心思想在于:將容器和算法分開,彼此獨(dú)立設(shè)計(jì),最后再以一個(gè)膠合劑連接在一起。而算法和數(shù)據(jù)容器的泛型化從技術(shù)角度來說并不難實(shí)現(xiàn),而如何將兩者聯(lián)系起來才是問題的關(guān)鍵所在。而迭代器恰恰扮演者這個(gè)角色。迭代器定義的位置最好是在容器內(nèi),將定義的任務(wù)交給了容器的設(shè)計(jì)者,因?yàn)槊恳环N容器都對(duì)應(yīng)一種迭代器,而定義在內(nèi)部也不會(huì)暴露容器的內(nèi)部元素。

看看下面的find函數(shù):

迭代器——STL關(guān)鍵所在

       可以看出find接受兩個(gè)迭代器和一個(gè)目標(biāo)對(duì)象。只要給予不同的迭代器find就可以對(duì)不同的容器進(jìn)行查找了。

       迭代器是一種類似指針的對(duì)象,而指針的各種行為中最常見也是最重要的便是內(nèi)容提領(lǐng)和成員訪問。因此,迭代器最重要的編程工作就是對(duì)operator*和operator->進(jìn)行重載。

       在學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)的時(shí)候list一直是一個(gè)重點(diǎn),以前也曾模擬實(shí)現(xiàn)過list,如今何不為list設(shè)計(jì)一個(gè)迭代器來將其數(shù)據(jù)容器與算法粘合起來呢?

       其接口及結(jié)點(diǎn)實(shí)現(xiàn)如下:

 template <class T>
struct __ListNode
{
	__ListNode<T>* _next;
	__ListNode<T>* _prev;
	T _data;

	__ListNode(const T& x = T())
		:_next(NULL)
		, _prev(NULL)
		, _data(x)
	{}
};

template <class T>
class List
{
public:
	typedef __ListNode<T> Listnode;
	
	List()
	{
		_head = new Listnode;
		_head->_next = _head;
		_head->_prev = _head;
	}

	~List()
	{}
	void Insert(const T& x);

	Iterator Erase(const T& x);

protected:
	Listnode* _head;

};

       模擬實(shí)現(xiàn)簡化版:

       我們自己實(shí)現(xiàn)的List也可以套用find函數(shù),只需對(duì)其進(jìn)行一個(gè)迭代器的設(shè)計(jì)就OK了。

       具體實(shí)現(xiàn)如下:

template<class T,class Ref,class Ptr>
struct __ListIterator
{
	typedef __ListIterator<T, Ref, Ptr> Self;
	typedef T ValueType;
	typedef Ptr Pointer;
	typedef Ref Reference;

	__ListNode<T>* _node;

	__ListIterator(__ListNode<T>* x)
		:_node(x)
	{}
	__ListIterator()
	{}


	bool operator==(const Self& s)
	{
		return _node == s._node;
	}

	bool operator!=(const Self& s)
	{
		return _node != s._node;
	}

	Reference operator*()
	{
		return _node->_data;
	}

	/*Reference operator->()
	{
		return _node->_data;
	}*/
	Self& operator++()			 //前置
	{
		_node = _node->_next;
		return *this;
	}

	Self& operator++(int)			
	{
		Self tmp(*this);
		_node = _node->_next;
		return tmp;
	}

	Self& operator--()
	{
		_node = _node->_prev;
		return *this;
	}

	Self& operator--(int)
	{
		Self tmp(*this);
		_node = _node->_prev;
		return tmp;
	}
};

       迭代器型別和trait編程:

       迭代器的型別主要有五種:value_type,catalog,reference,pointer,diffrence。分別代表這迭代器所指對(duì)象類型,迭代器類型,迭代器所指類型引用,迭代器所指類型指針,用什么類型表示迭代器之間距離(如int類型)。

      這里就不得不說下STL里面為了提取這些迭代器都有的特性用到的一個(gè)技法——trait。

STL為所有的迭代器提供一個(gè)型別類型,我們每定義一個(gè)迭代器都必須繼承該型別類型,這樣就可以保證符合STL的規(guī)范,防止遺漏。

template <class Category, class T, class Distance = ptrdiff_t,  
          class Pointer = T*, class Reference = T&>  
struct iterator {  
  typedef Category  iterator_category;  
  typedef T         value_type;  
  typedef Distance  difference_type;  
  typedef Pointer   pointer;  
  typedef Reference reference;  
};

       當(dāng)定義迭代器的時(shí)候,必須給定迭代器的特性。STL為提取迭代器的特性,提供了一個(gè)模板類iterator_trait,適用于所有的迭代器和原生指針。

       指針并非類型,因此需要偏特化成一個(gè)模板對(duì)應(yīng)指針的特性,可以看出,指針是隨機(jī)訪問迭代器類型。

       迭代器的類型有五種:輸入、輸出、前向、雙向、隨機(jī)訪問五種迭代器,輸入和輸出分別只讀和只寫,只能向前不能向后,前向迭代器可以進(jìn)行讀寫,只能向前,雙向迭代器可以向前和向后移動(dòng),但每次只能移動(dòng)一次,隨機(jī)訪問迭代器可以跳躍移動(dòng),與原生指針操作相同。

       STL中構(gòu)建了這五種類別,用于標(biāo)識(shí)迭代器的類別。

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

       可以看出繼承關(guān)系,使用template元編程技術(shù),之所以使用結(jié)構(gòu)體或類,是為了進(jìn)行參數(shù)推導(dǎo),將判斷在編譯期執(zhí)行而非運(yùn)行期,因?yàn)槊總€(gè)迭代器操作不同,因此需要不同的函數(shù)版本對(duì)應(yīng)不同迭代器。

       以上講的是迭代器的特性提取,還有類型的特性提取。類型的型別主要有五種:has_trivial_default_constructor、has_trivial_copy_constructor、has_trivial_assignment_operator、has_trivial_destructor、is_POD_type。

        迭代器失效:

       迭代器就不得不提到一個(gè)問題,迭代器失效。

       以vector為例,當(dāng)我們插入一個(gè)元素時(shí)它的預(yù)分配空間不夠時(shí),它會(huì)重新申請(qǐng)一段新空間,將原空間上的元素復(fù)制到新的空間上去,然后再把新加入的元素放到新空間的尾部,以滿足vector元素要求連續(xù)存儲(chǔ)的目的。而后原空間會(huì)被系統(tǒng)撤銷或征做他用,于是指向原空間的迭代器就成了類似于“懸垂指針”一樣的東西,指向了一片非法區(qū)域。如果使用了這樣的迭代器會(huì)導(dǎo)致嚴(yán)重的運(yùn)行時(shí)錯(cuò)誤就變得很自然了。這就是由迭代器失效引起的。當(dāng)然刪除一個(gè)元素時(shí)也可能引起迭代器失效。erase操作是在原空間上進(jìn)行的,假設(shè)有一個(gè)存有"12345"序列的vector<int>容器原本指向3的迭代器在我刪除2之后就變成指向4了。

      說了這么多似乎可以歸納一下迭代器失效的類型了:
      1.由于容器元素整體“遷移”導(dǎo)致存放原容器元素的空間不再有效,從而使得指向原空間的迭代器失效。

      2.由于刪除元素使得某些元素次序發(fā)生變化使得原本指向某元素的迭代器不再指向希望指向的元素。



向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI