1. 程式人生 > >C++之STL叠代器

C++之STL叠代器

初始 自身 sig 10個 sso emp 是把 由於 val

叠代器是一種檢查容器內元素並遍歷元素的數據類型。可以替代下標訪問vector對象的元素。

每種容器類型都定義了自己的叠代器類型,如 vector:

  1. vector<int>::iterator iter;

這符語句定義了一個名為 iter 的變量,它的數據類型是 vector<int> 定義的 iterator 類型。每個標準庫容器類型都定義了一個名為 iterator 的成員,這裏的 iterator 與叠代器實際類型的含義相同。

begin 和 end 操作

每種容器都定義了一對命名為 begin 和 end 的函數,用於返回叠代器。如果容器中有元素的話,由 begin 返回的叠代器指向第一個元素:
  1. vector<int>::iterator iter = ivec.begin();
上述語句把 iter 初始化為由名為 vector 操作返回的值。假設 vector 不空,初始化後,iter 即指該元素為 ivec[0]。由 end 操作返回的叠代器指向 vector 的“末端元素的下一個”。表明它指向了一個不存在的元素。如果 vector 為空,begin 返回的叠代器與 end 返回的叠代器相同。由 end 操作返回的叠代器並不指向 vector 中任何實際的元素,相反,它只是起一個哨兵(sentinel)的作用,表示我們已處理完 vector 中所有元素。 【備註:不用擔心begin和end在循環中的條件判斷。大膽使用吧!】

vector 叠代器的自增和解引用運算

叠代器類型可使用解引用操作符(dereference operator)(*)來訪問叠代器所指向的元素:
  1. *iter = 0;
解引用操作符返回叠代器當前所指向的元素。假設 iter 指向 vector 對象 ivec 的第一元素,那麽 *iter 和 ivec[0] 就是指向同一個元素。上面這個語句的效果就是把這個元素的值賦為 0。
叠代器使用自增操作符向前移動叠代器指向容器中下一個元素。從邏輯上說,叠代器的自增操作和 int 型對象的自增操作類似。對 int 對象來說,操作結果就是把 int 型值“加 1”,而對叠代器對象則是把容器中的叠代器“向前移動一個位置”。因此,如果 iter 指向第一個元素,則 ++iter 指向第二個元素。 由於 end 操作返回的叠代器不指向任何元素,因此不能對它進行解引用或自增操作。

叠代器的其他操作

另一對可執行於叠代器的操作就是比較:用 == 或 != 操作符來比較兩個叠代器,如果兩個叠代器對象指向同一個元素,則它們相等,否則就不相等。

叠代器應用的程序示例

1、使用叠代器和下標改變vector的內容

這個很簡單,請看代碼。
  1. #include <iostream>
  2. #include <string>
  3. #include <vector>
  4. int print_int_vector(std::vector<int> ivec)
  5. {
  6. for(std::vector<int>::size_type ix =0, j = 0; ix != ivec.size(); ++ix, ++j)
  7. {
  8. std::cout<<ivec[ix]<<" "; //加空格!
  9. }
  10. std::cout<<std::endl;
  11. return 0;
  12. }
  13. int main()
  14. {
  15. std::vector<int> ivec(10, 68); // empty vector
  16. print_int_vector(ivec);
  17. // reset all the elements in ivec to 0
  18. /*
  19. // 使用下標
  20. for (std::vector<int>::size_type ix = 0; ix != ivec.size(); ++ix)
  21. {
  22. ivec[ix] = 0;
  23. }
  24. */
  25. // equivalent loop using iterators to reset all the elements in ivec to 0
  26. for (std::vector<int>::iterator iter = ivec.begin(); iter != ivec.end(); ++iter)
  27. *iter = 0; // set element to which iter refers to 0
  28. print_int_vector(ivec);
  29. return 0;
  30. }

2、tuple功能的實現【不可變性】

const_iterator類型只能用於讀取容器內元素,但不能改變其值。
當我們對普通 iterator 類型解引用時,得到對某個元素的非 const。而如果我們對 const_iterator 類型解引用時,則可以得到一個指向 const 對象的引用),如同任何常量一樣,該對象不能進行重寫。 如果使用const_itreator進行重寫,編譯時會報錯! 使用 const_iterator 類型時,我們可以得到一個叠代器,它自身的值可以改變,但不能用來改變其所指向的元素的值。可以對叠代器進行自增以及使用解引用操作符來讀取值,但不能對該元素賦值。 【註意:不要把 const_iterator 對象與 const 的 iterator 對象混淆起來。聲明一個 const 叠代器時,必須初始化叠代器。一旦被初始化後,就不能改變它的值。】
  1. vector<int> nums(10); // nums is nonconst
  2. const vector<int>::iterator cit = nums.begin();
  3. *cit = 1; // ok: cit can change its underlying element
  4. ++cit; // error: can‘t change the value of cit
【註意:const_iterator 對象可以用於 const vector 或非 const vector,因為不能改寫元素值。const 叠代器這種類型幾乎沒什麽用處:一旦它被初始化後,只能用它來改寫其指向的元素,但不能使它指向任何其他元素。】 tuple不可變的實現需要使用const聲明!const vector<int> nums(10, 9);

總結

1、const_iterator需要註意:這個vector本身還是可變的,只不過對const_iterator類型解引用的對象不可變。 2、const叠代器也就是只能指向其所指向的元素,不能通過++等操作去指向其他元素。但是,所指向這個元素可以改變。 3、需要定義真正tuple,那就用const vector<int> nums(10, 9);來定義!此時,必須使用const_iterator 來獲取每個元素的值。

叠代器的算術操作

1、可以對叠代器對象加上或減去一個整形值。這樣做將產生一個新的叠代器,其位置在 iter 所指元素之前(加)或之後(減) n 個元素的位置。加或減之後的結果必須指向 iter 所指 vector 中的某個元素,或者是 vector 末端的後一個元素。加上或減去的值的類型應該是 vector 的 size_type 或 difference_type 類型,例子:
  1. int main()
  2. {
  3. std::vector<int> ivec(10, 68);
  4. print_int_vector(ivec);
  5. int i = 0;
  6. for (std::vector<int>::iterator iter = ivec.begin(); iter != ivec.end(); ++iter, i++)
  7. *iter = i; // set element to which iter refers to i
  8. print_int_vector(ivec);
  9. std::vector<int>::iterator iter = ivec.begin();
  10. iter += 100;
  11. std::cout<<*iter;
  12. return 0;
  13. }
本例子中ivec有10個元素,iter+=j,j在10以內都不會有錯(0~9),大於等於10則會出現溢出問題,編譯器,運行中間都不會報錯!可以加當然可以減。 2、iter1 - iter2: 該表達式用來計算兩個叠代器對象的距離,該距離是名為 difference_type 的 signed 類型 size_type 的值,這裏的 difference_type 是 signed 類型,因為減法運算可能產生負數的結果。該類型可以保證足夠大以存儲任何兩個叠代器對象間的距離。iter1 與 iter2 兩者必須都指向同一 vector 中的元素,或者指向 vector 末端之後的下一個元素。 3、可以用叠代器算術操作來移動叠代器直接指向某個元素,例如,下面語句直接定位於 vector 中間元素:
  1. vector<int>::iterator mid = vi.begin() + vi.size() / 2;
上述代碼用來初始化 mid 使其指向 vi 中最靠近正中間的元素。這種直接計算叠代器的方法,與用叠代器逐個元素自增操作到達中間元素的方法是等價的,但前者的效率要高得多。 4、任何改變 vector 長度的操作都會使已存在的叠代器失效。例如,在調用 push_back 之後,就不能再信賴指向 vector 的叠代器的值了。 請看例子:
  1. *iter = i; // set element to which iter refers to i
  2. ivec.push_back(i*2);
加上這句代碼沒問題,正確運行,但是,我們試圖在for循環裏面執行,即:
  1. {
  2. *iter = i; // set element to which iter refers to i
  3. ivec.push_back(i*2);
  4. }
則會莫名其妙退出!

C++之STL叠代器