官术网_书友最值得收藏!

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ā)更加靈活。

主站蜘蛛池模板: 皮山县| 扶余县| 哈巴河县| 淮安市| 余庆县| 莫力| 奎屯市| 饶河县| 武宁县| 中阳县| 闽侯县| 莱阳市| 双流县| 资阳市| 通海县| 额敏县| 德惠市| 安平县| 察哈| 沁源县| 佛坪县| 遂宁市| 剑阁县| 怀宁县| 逊克县| 积石山| 富顺县| 德惠市| 贺州市| 南安市| 东城区| 孝昌县| 黎平县| 绥滨县| 江西省| 阿图什市| 云梦县| 小金县| 旬邑县| 军事| 泸定县|