C++基礎之迭代器iterator
我們已經知道可以使用下標運算符來訪問string
對象的字符或vector
對象的元素,還有另一種更通用的機制也可以實現同樣的目的,這就是迭代器(iterator)
。
標准庫容器都可以使用迭代器,但是只有少數幾種才同時支持下標運算符。
類似於指針類型,迭代器
也提供了對對象
的間接訪問。就迭代器而言,其對象是容器中的元素或者string對象中的字符。使用迭代器可以訪問某一個元素,迭代器也能從一個元素移動到另外一個元素。迭代器和指針一樣,有無效和有效的區別。
有效的迭代器指向元素或者尾元素的下一個位置,其他情況都屬於無效的迭代器。
使用迭代器
能夠使用迭代器的變量類型擁有返回迭代器的方法。
begin()
方法負責返回指向第一個元素
的迭代器
end()
方法負責返回指向容器尾元素的下一個位置
的迭代器
// b表示v的第一個元素,e表示v尾元素的下一個位置
auto b = v.begin(), e = v.end(); // b和e的類型相同
特殊情況下:
如果容器為空,則
begin
和end
返回的是同一個迭代器。
迭代器運算符
運算符 | 含義 |
---|---|
*iter | 返回迭代器iter所指元素的引用 |
iter->mem | 解引用iter並獲取該元素的名為mem的成員,等價於*(iter).mem |
++iter | 令iter指向容器中的下一個元素 |
--iter | 令iter指向元素中的上一個元素 |
iter1 == iter2 | 判斷兩個迭代器是否相等 |
這使得迭代器就想下標一樣的好用,比如:
string s("come thing");
if (s.begin() != s.end()) {
auto it = s.begin();
*it = toupper(*it);
}
迭代器類型
就想不知道string
和vector
的site_type
成員到底是什么類型一樣,一般來說我們也不知道迭代器的精確類型。而實際上,那些擁有迭代器的標准庫類型都會使用iterator
和const_iterator
來表示迭代器的類型:
vector<int>::iterator it; // it能代表vector<int>的元素
string::iterator it2; // it2能代表string對象中的元素
vector<int>::const_iterator it3; // it3只能代表讀元素,不能代表寫元素
string::const_iterator it4; // it4只能讀字符,不能寫字符,即改變字符的值
const_iterator
和常量指針差不多,能讀取但不能修改他所指元素的值。
如果vector對象或string對象是一個常量,只能使用
const_iterator
結合解引用和成員訪問操作
解引用可以獲得迭代器所指的對象,如果該對象的類型恰好是個類,就有可能進一步訪問他的成員。例如:
vector<string> strs = {"string", "", "tingyugetc"};
for (auto it = strs.begin(); it != strs.end() ; ++it) {
if (it->empty()) {
cout << "now is in empty string" << endl;
}
}
上述的代碼中使用了箭頭運算符
, 箭頭運算符將解引用和成員訪問兩個操作結合在一起,他的作用和(*it).empty()
相同。
(*it).empty()
的圓括號必不可少,其含義是先執行括號內的解引用,接着解引用的結果在執行點運算符。如果不加括號,那么點運算符將由it執行,而不是it解引用的結果。
迭代器失效
某些對vector對象的操作會使迭代器失效.
謹記,但凡使用了迭代器的循環體,都不要想迭代器所屬的容器添加元素
迭代器的運算
迭代器的遞增運算令迭代器每次移動一個元素,所有的標准庫都有支持遞增運算符的迭代器。類似的,也能用==
和!=
對任意標准庫類型的兩個有效迭代器進行比較。
同樣的,可以令迭代器和一個整數值相加或相減,其返回值是向前或向后移動了若干個位置的迭代器,執行這樣的操作時,結果迭代器要么指向原vector對象內的一個元素要么指向尾元素的下一個位置。
比如,可以這樣:
// 計算得到最接近vi中間元素的一個迭代器
auto mid = vi.begin() + vi.size() / 2;
使用迭代器運算的一個經典算法是二分搜索。
auto beg = text.begin(), end = text.end();
auto mid = beg + (end - beg) / 2;
while (mid != end && *mid != found) {
if (found < *mid) {
end = mid;
} else {
beg = mid + 1;
}
mid = beg + (end - beg) / 2;
}