(原創) iterator到底是不是pointer? (C/C++) (STL)

Abstract
使用iterator時,能使用pointer的*、++、--與->等操作,到底iterator是不是pointer呢?

Introduction
一個很典型使用vector的STL程式碼。

1 #include <vector>
2 #include <iostream>
3 
4 using namespace std;
5 
6 int main() {
7   vector<int> ivec;
8   ivec.push_back(1);
9   ivec.push_back(2);
10   ivec.push_back(3);
11   ivec.push_back(4);
12  
13   for(vector<int>::iterator iter = ivec.begin(); iter != ivec.end(); ++iter)
14     cout << *iter << endl;
15 }


執行結果

1
2
3
4


13行

1 for(vector<int>::iterator iter = ivec.begin(); iter != ivec.end(); ++iter)
2   cout << *iter << endl;


iterator有兩個很神奇的操作:++iter與*iter,怎麼看都像在操作pointer,那到底iterator是不是pointer呢?

學C++的人大概分兩種背景的族群:
1.原來會C,有pointer概念

看到iterator的*、++、--與->等操作,一定會認為iterator就是個pointer,但我翻遍了C++ Primer 4th,就是沒看到它肯定地說『iterator就是poiner』,或說『iterator不是pointer』,留下一個曖昧的想像空間。若以C語言思考,iterator『應該』是pointer。

2.原來會C#、Java,有OO概念
『Everthing is object』,int是object,vector是object,所所以iterator『應該』也是object,但是iterator為什麼能用*、++、--與->等操作呢?那只是因為operator overloading的原因。況且C++對於pointer幾乎都有新的解決方案,如reference取代pass by pointer、vector取代array、string取代char *、STL containter取代dynamic alloction..等(請參閱(原創) C/C++哪些地方會用到pointer呢? (C/C++) (C))。 若以OO思維思考,iterator『應該』不是pointer。

到底誰說的才對呢?所謂『有code有真相』,我們直接拿SGI STL的source code來看看最常用的vector與list的iterator是如何實現。(我並沒有包含完整的SGI STL source,只截取我要解釋的部分來說明)。

stl_vector.h / C++

1 template <class T>
2 class vector {
3 public:
4   typedef T value_type;
5   typedef value_type* iterator; // pointer to T
6 }


5行

typedef value_type* iterator; // pointer to T


這裡很明顯,vector的iterator就是個pointer,看你T是什麼型別,就是指向T的pointer,所以對vector的iterator來說,它完全是一個pointer。 C語言背景的pointer概念在vector是正確的。

stl_list.h / C++

1 template <class T>
2 struct __list_node {
3   __list_node<T> * void_pointer;
4   void_pointer prev;
5   void_pointer next;
6   T data;
7 };
8  
9 template <class T, class Ref, class Ptr>
10 struct __list_iterator {
11   typedef Ref reference;
12   typedef Ptr pointer;
13   typedef __list_iterator<T, Ref, Ptr> self;
14   typedef __list_node<T> *link_type;
15   link_type node; // pointer to node
16  
17   reference operator*() const {
18     return (*node).data;
19   }
20  
21   pointer operator->() const {
22     return &(operator*());
23   }
24  
25   self& operator++() {
26     node = (link_type)((*node).next);
27     return *this;
28   }
29  
30   self operator--() {
31     node = (link_type)((*node).prev);
32     return *this;
33   }
34 };
35 
36 template <class T>
37 class list {
38 public:     
39  typedef __list_iterator<T, T&, T*>  iterator;
40 };


39行

typedef __list_iterator<T, T&, T*>  iterator;


list的iterator是__list_iterator的typedef,所以要繼續追__list_iterator是什麼東西。

9行

template <class T, class Ref, class Ptr>
struct __list_iterator {
  typedef Ref reference;
  typedef Ptr pointer;
  typedef __list_iterator
<T, Ref, Ptr> self;
  typedef __list_node
<T> *link_type;
  link_type node;
// pointer to node
 
  reference
operator*() const {
   
return (*node).data;
  }
 
  pointer
operator->() const {
   
return &(operator*());
  }
 
  self
& operator++() {
    node
= (link_type)((*node).next);
   
return *this;
  }
 
  self
operator--() {
    node
= (link_type)((*node).prev);
   
return *this;
  }
};


__list_iterator是定義list iterator的class, 所以OO背景說的沒錯,iterator不是pointer,它只是一個object,iterator的*、->、++、--都是operator overloading做出來的,而不是pointer本身的操作。 在++與--中,我們看到了node,node是什麼東西呢?繼續追下去...

14行

typedef __list_node<T> *link_type;
link_type node;
// pointer to node


我們知道list其實是資料結構的double linked list,由node所構成, 所以iterator的所有操作,本質上都是在操作node,再來看__list_node是如何定義的。

2行

template <class T>
struct __list_node {
  __list_node
<T> * void_pointer;
  void_pointer prev;
  void_pointer next;
  T data;
};


__list_node利用prev與next指向前一個node與後一個node,prev和next都是pointer,是個指向__list_node<T>的pointer,所以__list_iterator的++、--最後是靠pointer沒錯,不過list的iterator本身並不是pointer,而是個object,只是它用operator overloading模擬了pointer的操作而已。

Conclusion
iterator是不是pointer呢?要看container而定,由上可知,vector的iterator是pointer,list的iterator就不是pointer,而是object利用operator overloading使它表面上的操作像pointer而已,但並不是一個pointer。所以C語言背景與OO背景的人都是瞎子摸象,只摸到iterator的一部分。iterator除了因為vector因為較簡單,所以使用native pointer外,其他container的interator都是一種smart pointer,因為其操作跟pointer一樣,你可以將它當成pointer方式使用,不過他仍然不是pointer

iterator是泛型編程一個重要的概念,container只需知道如何使用iterator(*、++、--、->)即可,完全不需知道iterator的實際型別,而演算法可以完全獨立於container與iterator自行發展,只要設計時以iterator為對外interface即可。

See Also
(原創) C/C++哪些地方會用到pointer呢? (C/C++) (C)

Reference
侯捷 2002,STL源碼剖析,碁峰出版社
葉至軍 2007,C++ STL開發技術導引,人民郵電出版社

posted on 2008-07-21 13:22  真 OO无双  阅读(35944)  评论(1编辑  收藏  举报

导航