Abstract
使用iterator時,能使用pointer的*、++、--與->等操作,到底iterator是不是pointer呢?
Introduction
一個很典型使用vector的STL程式碼。
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 }
執行結果
2
3
4
13行
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++
2 class vector {
3 public :
4 typedef T value_type;
5 typedef value_type * iterator; // pointer to T
6 }
5行
這裡很明顯,vector的iterator就是個pointer,看你T是什麼型別,就是指向T的pointer,所以對vector的iterator來說,它完全是一個pointer。 C語言背景的pointer概念在vector是正確的。
stl_list.h / C++
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行
list的iterator是__list_iterator的typedef,所以要繼續追__list_iterator是什麼東西。
9行
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行
link_type node; // pointer to node
我們知道list其實是資料結構的double linked list,由node所構成, 所以iterator的所有操作,本質上都是在操作node,再來看__list_node是如何定義的。
2行
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開發技術導引,人民郵電出版社