迭代器類vector::iterator 和 vector::reverse_iterator 的實現、迭代器類型、常用的容器成員


一、迭代器

迭代器是泛型指針

普通指針可以指向內存中的一個地址

迭代器可以指向容器中的一個位置

STL的每一個容器類模版中,都定義了一組對應的迭代器類。使用迭代器,算法函數可以訪問容器中指定位置的元素,而無需關心元素的具體類型。



下面來稍微看一下vector<class>::iterator 和 vector<class>::reverse_iterator 的源碼:

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
 

template < class _Ty,
         class _Alloc >
class _Vector_val
    : public _CONTAINER_BASE_AUX_ALLOC<_Alloc>
{
    // base class for vector to hold allocator _Alval
protected:
    _Vector_val(_Alloc _Al = _Alloc())
        : _CONTAINER_BASE_AUX_ALLOC<_Alloc>(_Al), _Alval(_Al)
    {
        // construct allocator from _Al
    }

    typedef typename _Alloc::template
    rebind<_Ty>::other _Alty;

    _Alty _Alval;   // allocator object for values
};

template < class _Ty,
         class _Ax >
class vector
    : public _Vector_val<_Ty, _Ax>
{
    // varying size array of values
public:
    .....
    typedef _Vector_val<_Ty, _Ax> _Mybase;
    typedef typename _Mybase::_Alty _Alloc;  //_Alloc 的定義所在
    typedef _Vector_iterator<_Ty, _Alloc> iterator;
    typedef _Vector_const_iterator<_Ty, _Alloc> const_iterator;

    //  friend class _Vector_iterator<_Ty, _Alloc>;
    friend class _Vector_const_iterator<_Ty, _Alloc>;

    typedef std::reverse_iterator<iterator> reverse_iterator;
    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
    .......
};

template < class _Ty,
         class _Alloc >
class _Vector_iterator
    : public _Vector_const_iterator<_Ty, _Alloc>
{
    // iterator for mutable vector
public:
    typedef _Vector_iterator<_Ty, _Alloc> _Myt;
    typedef _Vector_const_iterator<_Ty, _Alloc> _Mybase;
    .......
};

template < class _Ty,
         class _Alloc >
class _Vector_const_iterator
    : public _Ranit < _Ty, typename _Alloc::difference_type,
      typename _Alloc::const_pointer, typename _Alloc::const_reference >
{
    // iterator for nonmutable vector
public:
    .....
    typedef typename _Alloc::pointer _Tptr;
   typedef random_access_iterator_tag iterator_category;
   typedef _Ty value_type;
   typedef typename _Alloc::difference_type difference_type;
   typedef typename _Alloc::const_pointer pointer;
  typedef typename _Alloc::const_reference reference;
 typedef const value_type _FARQ *const_pointer;
 typedef const value_type _FARQ& const_reference;
    ....
    _Tptr _Myptr;   // offset of element in vector
};

template<class _Ty>
class allocator
    : public _Allocator_base<_Ty>
{
    // generic allocator for objects of class _Ty
public:
    ......
    typedef _Allocator_base<_Ty> _Mybase;
    typedef typename _Mybase::value_type value_type;
    typedef value_type _FARQ *pointer;
    typedef value_type _FARQ& reference;
    ...
};

// TEMPLATE CLASS _Allocator_base
template<class _Ty>
struct _Allocator_base
{
    // base class for generic allocators
    typedef _Ty value_type;
};

template<class _RanIt>
class reverse_iterator
    : public _Revranit<_RanIt, iterator<...> >
{
    // wrap iterator to run it backwards
    ........
    typedef reverse_iterator<_RanIt> _Myt;
    typedef _RanIt iterator_type;
    ..............

};

// TEMPLATE CLASS _Revranit
template < class _RanIt,
         class _Base >
class _Revranit
    : public _Base
{
    // wrap iterator to run it backwards
    ....
protected:
    _RanIt current; // the wrapped iterator
};

typedef _Vector_iterator<_Ty, _Alloc> iterator; 可知iterator 只是類型定義,而_Vector_iterator 又繼承自 _Vector_const_iterator,這

個類有個成員_Tptr _Myptr;  進一步看_Tptr 可以知道類型是value_type*, 假設現在使用的容器是vector<int>,那么value_type 也就是

即包裝了一般的指針。很明顯地,iterator 類里面一定重載了

operator*, ->, ++, -- 等操作符,而這些操作符實際上還是對一般的指針_Myptr 進行操作。舉operator* 來說:

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
 
// iterator
reference  operator*() const
{
    // return designated object
    return ((reference) **(_Mybase *)this);
}

// const_iterator
reference operator*() const
{
    // return designated object

    .....
    return (*_Myptr);
}

(_Mybase *)this就是const_iterator*,*(_Mybase *)this就是const_iterator 對象,**(_Mybase *)this就是調用const_iterator

的 operator*(), 即 返回*_Myptr,即指向的元素,iterator 的 operator* 返回的是引用 reference ,這其實是在allocator 類中定義的const_reference,

即 const value_type&, 假設現在的容器是vector<int> ,那么返回的也就是const int& ,即不能將其作為左值進行賦值,但能作為右值,如 cout<<*it;

同樣地, iterator 的 operator++ 也調用了 const_iterator 的 operator++, 在函數里面也是執行  ++_Myptr; 的操作,返回的是const_iterator& ,而從

iterator 的 operator++ 返回的是iterator& 。

typedef std::reverse_iterator<iterator> reverse_iterator; 再來看 reverse_iterator,繼承自_Revranit, 這個類有個成員 _RanIt current; 

也就是說有個 iterator 類成員,即包裝了一個iterator 類成員,從這個角度看,reverse_iterator 也可以算是一個適配器,利用 iterator 

類的一些操作完成自身的功能。

××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

上面介紹的是vector::iterator ,比如 list::iterator 實現是類似的,內部成員也是一個指針,不過是指向Node 結點的指針,如:

_Nodeptr _Ptr;// pointer to node

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 
#include <vector>
#include <list>
#include <iostream>

using namespace std;

int main(void)
{
    vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);

    vector<int>::iterator it;
    for (it = v.begin(); it != v.end(); ++it)
    {
        cout << *it << ' ';
    }
    cout << endl;

    vector<int>::reverse_iterator ri;
    for (ri = v.rbegin(); ri != v.rend(); ++ri)
    {
        cout << *ri << ' ';
    }
    cout << endl;


    list<int> l;
    l.push_back(1);
    l.push_back(2);
    l.push_back(3);

    list<int>::iterator it2;

    for (it2 = l.begin(); it2 != l.end(); ++it2)
    {
        cout << *it2 << ' ';
    }
    cout << endl;

    return 0;
}


二、迭代器的類型 iterator_category

輸入迭代器

可以用來從序列中讀取數據

輸出迭代器

允許向序列中寫入數據

前向迭代器

既是輸入迭代器又是輸出迭代器,並且可以對序列進行單向的遍歷

雙向迭代器

與前向迭代器相似,但是在兩個方向上都可以對數據遍歷

隨機訪問迭代器

也是雙向迭代器,但能夠在序列中的任意兩個位置之間進行跳轉

下圖是不同類型的迭代器能夠實現的操作:


1、The standard-library container classes all support bidirectional iterators.

of curse the const iterator only meets the requirements for input iterators.

2、The vector and deque iterators are random-access iterators. however, the list iterator is not; it supports only bidirectional iterators.etc,it does not support [] operation.

3、If c is a container that supports push_back, then back_inserter(c)  is an output iterator that meets no other iterator requirements.

4、The stream iterators are defined in the <iterator> header,  the istream_iterator<class name> meets the requirements for input iterators; the ostream_iterator<class name>  meets the requirements for output iterators.

 we can use it like this:

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
 
vector< int> v;
// read ints from the standard input and append them to v
// istream_iterator<int>() indicate "EOF"
copy(istream_iterator<int>(cin), istream_iterator<int>(), back_inserter(v));


// write the elements of v each seperated from other by a space
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " ");

     // no seperation between elements!
     copy(v.begin(), v.end(), ostream_iterator<int>(cout);


不同的迭代器支持不同的操作集,而各種算法也要求相應的迭代器具有最小的操作集。因此,可以將算法的迭代器分為下面五類:


  除了輸出迭代器,其他類別的迭代器形成了一個層次結構:需要低級類別迭代器的地方,可使用任意一種更高級的迭代器。例如,對於需要輸入迭代器的算法,可傳遞前向、雙向或隨機訪問迭代器調用該算法。而反之則不行。注意:向算法傳遞無效的迭代器類別所引起的錯誤,無法保證會在編譯時被捕獲到。
   map, set, list類型提供雙向迭代器,而string, vector和deque容器上定義的迭代器都是隨機訪問迭代器,用作訪問內置數組元素的指針也是隨機訪問迭代器。istream_iterator是輸入迭代器,ostream_iterator是輸出迭代器。
   另外,雖然map和set類型提供雙向迭代器,但關聯容器只能使用這部分算法的一個子集。因為關聯容器的鍵是const對象。因此,關聯容器不能使用任何寫序列元素的算法。只能使用與關聯容器綁在一起的迭代器來提供用於讀操作的實參。因此,在處理算法時,最好將關聯容器上的迭代器視為支持自減運算的輸入迭代器,而不是完整的雙向迭代器。
  最后需要注意的是,stack、queue、priority_queue 都不支持任一種迭代器,它們都是容器適配器類型,stack是vector/deque/list對象創建了一個先進后出容器,queue是deque或list對象創建了一個先進先出容器,priority_queue是vector/deque創建了一個排序隊列。

三、常用的容器成員

下面列舉的成員中,有一些是所有容器共有的,有些是特有的,注意區別:








四、迭代器失效的問題(摘自 http://blog.csdn.net/hackbuteer1/article/details/7734382)

vector迭代器的幾種失效的情況: 
1、當插入(push_back)一個元素后,end操作返回的迭代器肯定失效。
2、當插入(push_back)一個元素后,capacity返回值與沒有插入元素之前相比有改變,則需要重新分配整個容器,此時first和end操作返回的迭代器都會失效。
3、當進行刪除操作(erase,pop_back)后,指向刪除點的迭代器全部失效;指向刪除點后面的元素的迭代器也將全部失效。


 deque迭代器的失效情況: 在C++Primer一書中是這樣限定的: 
1、在deque容器首部或者尾部插入元素不會使得任何迭代器失效。 
2、在其首部或尾部刪除元素則只會使指向被刪除元素的迭代器失效。
3、在deque容器的任何其他位置的插入和刪除操作將使指向該容器元素的所有迭代器失效。


 list的迭代器好像很少情況下會失效,也許就只是在刪除的時候,指向被刪除節點的迭代器會失效吧,其他的還沒有發現。
先看兩條規制:
1、對於節點式容器(map, list, set)元素的刪除、插入操作會導致指向該元素的迭代器失效,其他元素迭代器不受影響。
2、對於順序式容器(vector)元素的刪除、插入操作會導致指向該元素以及后面的元素的迭代器失效。


眾所周之當使用一個容器的insert或者erase函數通過迭代器插入或刪除元素"可能"會導致迭代器失效,因此建議我們獲取insert或者erase返回的迭代器,以便用重新獲取新的有效的迭代器進行正確的操作:
代碼如下:

[cpp]  view plain copy
 
  1. iter = vec.insert(iter);  
  2. iter = vec.erase(iter);  

參考:

C++ primer 第四版
Effective C++ 3rd
C++編程規范


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM