我們知道,迭代器常用來訪問容器中的元素。在使用迭代器的方式上來看,和指標非常的類似,甚至於就已經當作指標來使用了。事實上,迭代器的作用就是為了提供一種訪問資料的方式。
容器(container)作為標準模板庫中的乙個核心內容,給我們提供了非常強大的資料結構的支援,以便於我們能夠更加方便、高效的實現我們的演算法。為了方便我們對容器中的元素進行操作,標準模板庫還給我們提供了另乙個強大的功能,那就是迭代器。因此,大家把迭代器作為連線容器和演算法的紐帶。
迭代器實際上是對資料訪問的一種抽象,他不是乙個固定的物件。由於不同的資料結構具有不同的訪問方式,因此不同的容器需要給我們提供不同的迭代器。
迭代器的行為類似於指標,因此它也有類似指標的操作,主要分為下面五類操作:
操作作用
讀操作返回迭代器指向元素的引用(=*iter)
寫操作對迭代器所指元素進行更改(*iter=)
成員訪問
訪問迭代器所指元素的成員(iter->member、)
迭代令迭代器指向前(後)乙個元素(iter++、iter–、++iter、–iter)
比較對迭代器物件進行比較(==、!=、>、<、>=、<=)
注意,並不是所有的迭代器都具有這5個功能!
根據迭代器能執行的操作可將迭代器分為下面五類:
類別操作
輸入迭代器
*p=、++
輸出迭代器
=*p、->、++、==、!=
前向迭代器
*p=、=*p、->、++、==、!=
雙向迭代器
*p=、=*p、->、++、- -、==、!=
隨機訪問迭代器
*p=、=*p、->、、++、- -、+、-、+=、- =、==、!= 、>、<、>=、<=
stl中不同容器支援不同的迭代器,下面是它們支援的迭代器型別:
容器迭代器型別
vector
隨機訪問迭代器
list
雙向迭代器
deque
隨機訪問迭代器
set雙向迭代器
map雙向迭代器
另外,容器介面卡不支援迭代器。
1.定義及初始化
vector提供了下面幾種迭代器,這裡以int為例:
vector::iterator
vector::const_iterator
vector::reverse_iterator
vector::const_reverse_iterator_iterator
前者可通過迭代器進行讀寫,而後者不能通過迭代器進行寫操作。
#include
#include
using namespace std;
intmain()
;const vector<
int>
&vec2 = vec1;
vector<
int>
::iterator it1 =vec1.
begin()
; vector<
int>
::const_iterator it2 = vec2.
end();
return0;
}
注1:vec.begin()函式返回指向容器中第乙個元素的迭代器;vec.end()函式返回指向容器中最後乙個元素後乙個位置的迭代器。不要利用vec.end()返回的迭代器進行讀寫等操作,這樣可能導致程式崩潰。
注2:vec.begin()和vec.end()的返回型別為iterator或者const_iterator,這取決於vector的型別。如程式中的vec2是vec1的常引用,因此vec2.end()返回型別為const_iterator,所以需要it2的型別需要宣告為const_iterator。
注3:如果要獲取普通vector的const_iterator或者reverse_iterator,還可以使用vector提供的vec.cbegin()、vec.rbegin()或者是vec.crbegin()等函式。當然,我們還可以使用c++提供的自動型別auto。
#include
#include
using namespace std;
intmain()
;const vector<
int>
&vec2 = vec1;
auto it1 = vec1.
begin()
;auto it2 = vec2.
end();
return0;
}
2.遍歷
迭代器最重要的功能就是對容器中的元素進行訪問,下面是利用迭代器對容器進行遍歷的程式:
順序遍歷
#include
#include
using namespace std;
intmain()
;for
(auto it = vec1.
begin()
; it != vec1.
end(
); it++
) cout <<
*it <<
" ";
cout << endl;
return0;
}
1 3 5 7 9
逆序遍歷
#include
#include
using namespace std;
intmain()
;for
(auto it = vec1.
rbegin()
; it != vec1.
rend()
; it++
) cout <<
*it <<
" ";
cout << endl;
return0;
}
9 7 5 3 1
for迴圈中,迴圈的結束條件為」it!=vec1.end()」,正說明了vec1.end()函式返回的是容器最後乙個元素後乙個位置的迭代器。此外,這裡沒有用」it」、「<=」、「>=」對迭代器進行比較。因此為了統一,迴圈條件都寫為」it!=vec1.end()」的形式。當然,對於vector和deque,使用」it注意,利用迭代器對容器進行遍歷的方式並不是c++提供的最簡潔的方式。c++還提供了range_based for和lambda函式等方式來對容器進行遍歷,這裡不展開比較。
在討論容器的時候我們提到,當容器中元素增加時,如果當前分配的空間已滿,會重新分配一塊更大的空間,然後執行複製、銷毀等操作。那麼這個時候迭代器所指向的元素可能發生了變化或者根本已經不存在了,這就是所謂的迭代器失效。
當然,除了增加元素還有許多使迭代器失效的情況,例如刪除、插入等。
下面是乙個迭代器失效的簡單例子:
#include
#include
#include
using namespace std;
intmain()
;auto it_begin = vec1.
begin()
;auto it_end = vec1.
end();
vec1.
pop_back()
;for(
auto it = it_begin; it != it_end; it++
) cout << endl;
return0;
}
上面的程式中,在第7、8行宣告了兩個迭代器並初始化為vec1.begin()和vec1.end(),隨後執行了pop_back方法將容器中最後乙個元素移出了,然後企圖繼續利用上述兩個迭代器對容器元素進行遍歷。執行的結果告訴我們這裡根本得不到執行結果,使用已經失效的迭代器會發生非常嚴重的問題,使得程式崩潰。
因此,我們在使用迭代器的時候應該知道什麼操作會使得結構體失效,從而採取措施進行避免。
STL之迭代器
除了為每個容器定義的迭代器之外,標準庫在標頭檔案iterator中還定義了額外幾種迭代器,包括 1 插入迭代器 insert iterator 被繫結到乙個容器上,可用來向容器插入元素。2 流迭代器 stream iterator 被繫結到輸入輸出流,可用來遍歷所關聯的io流。3 反向迭代器 rev...
STL之迭代器
1 每一種容器都有自己的迭代器 2 所有的迭代器介面都是一樣的 3 在整個標準庫中,經常使用形參為一對迭代器的建構函式 4 常用的迭代器操作 iter iter iter iter1 iter2,iter1 iter2 5 vector和deque容器的迭代器的額外操作 iter n,iter n,...
STL之迭代器
除了每個容器定義的迭代器之外,在標準庫標頭檔案iterator中還定義了額外幾種迭代器 1.插入迭代器 插入迭代器是一種迭代器介面卡,它接受乙個容器,返回乙個迭代器,能實現向容器新增資料 插入迭代器有3中型別,都是返回乙個容器的插入迭代器,區別是所插入的位置不同 1 back inserter ve...