簡體   English   中英

什么是迭代器,C++?

[英]What are Iterators, C++?

C++中的迭代器是什么?

迭代器是遍歷對象集合的一種方式。 通常,它們允許您以類似於使用指針訪問經典C數組的方式順序訪問STL(標准模板庫)容器。 要通過迭代器訪問對象,可以像C指針一樣取消引用它。 要訪問集合中的下一個對象,請使用increment(++)運算符。 某些容器具有多種迭代器,允許您以不同方式遍歷集合。

雖然它最初看起來相當明顯,但這實際上是一個比你可能意識到的更深層次的問題。 與Paul McJones一起,Alexander Stepanov(原版的設計師,對於任何不了解這一點的人)最近發布了一本名為Elements of Programming (又名EOP)的書。 該書第六章的全部內容專門用於迭代器,本書的其余部分也與迭代器密切相關。 任何真正想要詳細了解迭代器的人都可以考慮閱讀本書。

警告:EOP 適合膽小的人。 它相對較短(約260頁),但相當密集。 從經驗來看,早期的進展有點令人不安。 我對第一章的初步反應或多或少“很好,這很明顯,幾乎不值得一讀。畢竟我在上周之前開始編程!”

幸運的是,我確實看了練習,並嘗試做了幾個 - 盡管我認為這些主題很明顯,但練習需要嚴格的證明。 這有點像被要求證明(在數學意義上)水是濕的。 你最后只需要閱讀這一章只是為了超越你已經知道答案的先入為主的觀念,所以你可以看看真正的問題 - “濕”真正意味着什么; “濕潤”的基本特征是什么?

http://en.wikipedia.org/wiki/Iterator

可以讓你逐個瀏覽數組中的所有內容。

在c ++中,我認為你在談論“for_each”......據我所知,與C#這樣的語言不同,C ++實際上沒有“foreach”。 但是,標准模板庫有它。

從p。 加速C ++ 80:

迭代器是一個值

  • 標識容器中的容器和元素
  • 讓我們檢查存儲在該元素中的值
  • 提供在容器中的元素之間移動的操作
  • 以與容器可以有效處理的方式對應的方式限制可用操作

它們是序列中位置的表示。 它們本身就只是好奇心,但是當取消引用時,它們會導致序列中所包含的值代表它所代表的位置。

如果您使用過 Java 或 Python 等高級語言,您可能已經注意到 C++ 沒有任何內置的復雜類型,只有intdoublechar等基本類型。 由於 C++ 的設計非常高效,因此每當您需要使用任何用於保存其他值的集合類型時,創建一個新的自定義類就很有意義。 事實上,這就是 C++ 結合低級控制和高級抽象的方式。

標准模板庫提供了這些類的標准化集合,您可以使用這些類在單個實體下保存多個值。 創建它們的主要原因是原始 C 數組不夠靈活,並且容器為開發人員提供了更流暢的開發體驗,因為它們:

  • 無需任何開發人員的努力即可動態擴展和收縮;
  • 為數據提供多個有用的接口( size()upper_bound()等);
  • 通過Resource Acquisition is Initialisation簡化內存管理。

到目前為止,一切都很好。 vectorlist等標准容器為開發人員提供了更大的靈活性,而不會損失太多性能。 但是,由於它們是使用 C++ 語義定義的自定義類,因此它們還需要提供一種方法來訪問它們所持有的數據。 有人可能會爭辯說,一個簡單的operator[]next()方法就可以做到這一點,事實上你可以做到這一點,但是 STL 從 C 中獲得靈感並創建了一種能夠訪問容器項而不依賴於容器對象本身的方法:迭代器

在幕后,迭代器只不過是一個對象,它用一些運算符重載包裝指向一個值的指針。 您可以像使用指向數組的指針一樣使用迭代器:

  • 即使您無權訪問容器對象本身,您也可以傳遞迭代器並遍歷容器;
  • 您可以通過遞增取消引用和移動迭代器。

這是迭代器的主要目的:用作指向容器項的指針。 因為不同的容器以不同的方式存儲不同的項目( std::vector使用連續的內存塊, std::list將節點存儲在別處與指針連接, std::map使用關聯數組中的散列鍵),迭代器可用於提供一個通用的將在每個單獨的容器中實現的接口。 事實上,這就是允許使用基於范圍的 for 循環枚舉std::vectorstd::arraystd::map等容器的原因:

std::vector<int> grades = {4, 5, 1, 8, 10};
for (int grade : grades) std::cout << grade << " ";
//-> 4 5 1 8 10

這個 for 循環只是使用迭代的語法糖:

std::vector<int> grades = {4, 5, 1, 8, 10};
std::vector::iterator it = grades.begin();
for (; it != grades.end(); ++it) std::cout << grade << " ";
//The output is the same.

您可能已經注意到迭代器使用的一些常見接口,正是它們:

  • 重載*運算符以取消引用項目;
  • 重載++運算符以將迭代器向前移動一項;
  • 重載==!=運算符以比較它們是否指向相同的值;
  • 通常被定義為一個嵌套的友元類(您可以使用<container>::iterator訪問它們,盡管您可以將迭代器完全定義為一個單獨的類。

另請注意,所有支持容器的容器都應提供begin()方法,該方法將迭代器返回到第一個項目,以及end()以將迭代器返回到最后一個項目之后的項目。 它指向最后一個位置之后的位置的原因是因為它用於評估迭代器是否用盡所有項目:如果end()指向最后一個項目,則循環條件將是it <= grades.end() 取而代之的是指向容器之后的下一個位置,允許它使用簡單的 less 檢查對其進行評估,這與數組以零開頭的原因相同。 除了它們之外,還有rbegin()rend()函數提供從末尾到開頭的反向迭代器,它的++運算符實際上是到開頭。

實現自定義迭代器

為了完全清楚,讓我們為普通數組的包裝器實現我們自己的自定義迭代器。

template<typename T, unsgined int Capacity> class Array {
    T data[Capacity];
    int count;
    friend class Iterator;
public:
    Array(const std::initializer_list args) {
       for (int step = 0; step < args.size(); step++)
          data[step] = args[step;
    }
    int size() : count;
    T& operator[](int index) {
        if (index < 0 || index > capacity) throw
           std::out_of_range("Index out of range.");
        return data[index];
    }
    Iterator<T> begin() {
       return &data; //Pointer to array yield the
                     //address to their first item.
    }
    Iterator<T> end() {
       return &(data + Capacity);
    }
};

template<typename T> class Iterator {
    T* reference;
public:
    Iterator(const Array<T>& array) {
       reference = array.begin();
    }
    T* operator*() {
       return reference;
    }
    Iterator<T> operator++() {
       return ++reference; //This is array-specific implementation detail.
    }
    bool operator!=(const Iterator<T>& other) : *reference != *other;
};

int main() {
   Array<int> array = {4, 5, 10, 12, 45, 100};
   Iterator<int> it = array.begin();
   while (it != array.end()) {
      std::cout << *it;
      ++it;
   }
   return 0;
}

如您所見,將迭代器划分為單獨的類也需要單獨指定其類型,這就是為什么通常將其定義為容器中的嵌套類的原因。

還有<iterator>標頭為標准迭代器提供了一些有用的工具,例如:

  • next()遞增迭代器的函數;
  • prev()函數返回迭代器之前的步驟;
  • advance(int)將迭代器向前移動 n 步;
  • 用於比較迭代器的重載運算符;
  • 其他與迭代相關的添加。

如果您需要為您自己的高度特定的容器編寫自定義迭代器,而 STL 中不存在,您應該記住迭代器用作容器和算法之間的中間值,並且對於您自己的容器,您應該選擇合適的類型迭代器(輸入、輸出、前向、雙向或隨機訪問)支持一些標准算法的出手。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM