- C++服務器開發(fā)精髓
- 張遠龍
- 1196字
- 2021-07-23 18:22:10
1.8 Range-based循環(huán)語法
大多數(shù)語言都支持for-each語法遍歷一個數(shù)組或集合中的元素。在C++98/03規(guī)范中,對于一個數(shù)組int arr[10],如果我們想要遍歷這個數(shù)組,則只能使用遞增的計數(shù)去引用數(shù)組中的每個元素:

在C++11規(guī)范中有了for-each語法,可以這么寫:

對于1.7節(jié)中遍歷std::map的內(nèi)容,我們也可以使用這種語法:

for-each語法雖然很強大,但是有兩個需要注意的地方。
◎ for-each中的迭代器類型與數(shù)組或集合中元素的類型完全一致,而原來使用老式語法迭代 stl容器(如 std::map)時,迭代器 iter的類型是 stl容器中元素的指針類型。因此,在上面例子的老式語法中,iter是一個指針類型(std::pair<std::string,std::string>*),使用 iter->second 去引用鍵值;而在 for-each 語法中,iter 與容器中元素的數(shù)據(jù)類型(std::pair<std::string,std::string>)相同,因此使用iter.second可直接引用鍵值。
◎ 在 for-each 語法中,對于復雜的數(shù)據(jù)類型,迭代器是原始數(shù)據(jù)的拷貝,而不是原始數(shù)據(jù)的引用。什么意思呢?來看一個例子:

我們遍歷容器 v,試圖將 v 中元素的值都修改成“hello”,在實際執(zhí)行時卻達不到我們想要的效果。這就是上文說的for-each中的迭代器是元素的拷貝,所以這里只是將每次的拷貝都修改成“hello”,原始數(shù)據(jù)并不會被修改。我們可以將迭代器修改成原始數(shù)據(jù)的引用:

這樣就達到修改原始數(shù)據(jù)的目的了。這是使用for-each比較容易出錯的地方。對于容器中的復雜數(shù)據(jù)類型,我們應該盡量使用這種引用原始數(shù)據(jù)的方式,減少不必要的拷貝構(gòu)造函數(shù)調(diào)用開銷:


1.8.1 自定義對象如何支持Range-based循環(huán)語法
介紹了這么多,如何讓自定義對象支持Range-based循環(huán)語法呢?為了支持這種語法,這個對象至少需要實現(xiàn)如下兩個方法:

上面的Iterator是自定義數(shù)據(jù)類型的迭代子類型,這里的Iterator類型必須支持如下三種操作(原因在下文中會解釋)。
◎ operator++(自增)操作,可以在自增之后返回下一個迭代子的位置。
◎ operator!=(判不等操作)操作。
◎ operator*(解引用,dereference)操作。
下面是一個自定義對象支持for-each循環(huán)的例子:


注意:在以上代碼中,迭代子Iterator是T*,是指針類型,本身就支持operator++和operator!=操作,所以這里并沒有提供這兩個方法的實現(xiàn)。那么為什么迭代子要支持operator++和operator!=操作呢?我們來看一下編譯器是如何實現(xiàn)這種for-each循環(huán)的。
1.8.2 for-each循環(huán)的實現(xiàn)原理
上述for-each循環(huán)可被抽象成如下公式:


C++14標準是這樣解釋上面的公式的:

在這個循環(huán)中,begin-expr返回的迭代子__begin 需要支持自增操作,且每次循環(huán)時都會與end-expr返回的迭代子__end做判不等比較,在循環(huán)內(nèi)部通過調(diào)用迭代子的解引用(*)操作取得實際的元素。這就是上文說的迭代子對象需要支持 operator++、operator!=和operator*的原因了。
但是在上面的公式中,一個逗號表達式中的“auto__begin=begin-expr,__end=end-expr;”只使用了一個類型符號 auto,導致起始迭代子__begin和結(jié)束迭代子__end 是同一類型,這樣不太靈活。在某些設計中,可能希望結(jié)束迭代子是另一種類型。
因此在C++17標準中要求編譯器解釋for-each循環(huán)為如下形式:


看到了吧,代碼第 2 行和第 3 行將獲取起始迭代子__begin 和結(jié)束迭代子__end 分開寫,這樣這兩個迭代子就可以是不同的類型了。雖然類型可以不一樣,但這兩種類型之間仍然支持operator!=操作。C++17對C++14的這種改變,對舊的代碼不會產(chǎn)生任何影響,但可以讓之后的開發(fā)更加靈活。
- Microsoft Application Virtualization Cookbook
- Leap Motion Development Essentials
- Java從入門到精通(第4版)
- 數(shù)據(jù)結(jié)構(gòu)與算法JavaScript描述
- MariaDB High Performance
- 假如C語言是我發(fā)明的:講給孩子聽的大師編程課
- 嚴密系統(tǒng)設計:方法、趨勢與挑戰(zhàn)
- 高級語言程序設計(C語言版):基于計算思維能力培養(yǎng)
- Angular開發(fā)入門與實戰(zhàn)
- Illustrator CS6設計與應用任務教程
- JQuery風暴:完美用戶體驗
- Flink核心技術:源碼剖析與特性開發(fā)
- 算法超簡單:趣味游戲帶你輕松入門與實踐
- Java程序設計
- Learn Linux Quickly