2012-04-19 27 views
1

我使用std :: map作爲算法的數據存儲器,但由於某種原因,我需要以某種方式控制map元素的訪問。我們知道可以通過直接調用operator [key]來訪問地圖的元素。但是,如果密鑰不存在,並且每次調用operator [key]時都會自動創建該值,其值初始化爲'ZERO'。但在我的算法中,我將通過限制只有當存在鍵和值不爲零時才能修改元素來控制訪問。例如,如果地圖具有以下元素(3,2),(1,0),(4,0),(2,7),則只能修改(3,2)和(2,7)。我知道在我修改元素之前,我可以在map :: find(key)或map :: count(key)的任何位置添加一些代碼,但它太多了,所以我想寫下我自己的容器,如下所示在C++中請求自定義迭代器的建議我的自定義容器

class MyContainer; 

template <typename T> class myiterator :public iterator<forward_iterator_tag, T> 
{ 
    friend class MyContainer; 
    private: 
    T *pointer; 
    myiterator(T *pointer):pointer(pointer) {} 

    public: 
    T& operator*() {return (*pointer);} 

    const myiterator<T>& operator++() 
    { 
     pointer->current_iterator++; 
    return *this; 
    } 

    bool operator!=(const myiterator<T>& other) const 
    { 
     return pointer->current_iterator != other.pointer->current_iterator; 
    } 

    bool isEnd(void) const 
    { 
     return pointer->current_iterator == pointer->end_iterator; 
    } 
    }; 

    class MyContainer 
    { 
    friend class myiterator<MyContainer>; 
    public: 
     typedef myiterator<MyContainer> iterator; 

    private: 
     map<int, int> data; 
     map<int, int>::iterator current_iterator, end_iterator; 

    public: 
     MyContainer() {current_iterator = data.begin(); } 

     void addDataPair(int key, int value) {data[key] = value;} 

     int first() {return (*current_iterator).first;} 
     int second() {return (*current_iterator).second;} 

     // initialize the current_iterator to the begin of the data (map) and set the end iterator too 
     iterator begin() 
     { 
     current_iterator = data.begin(); 
     end_iterator = data.end(); 
     return myiterator<MyContainer>(this); 
     } 

     // return the container w/ current_iterator point to where the key is 
     MyContainer &operator[](int key) 
     { 
     current_iterator = data.find(key); 
     return (*this); 
     } 

     // only increase the value by one when the key does exist and with initial value non-zero 
     void operator++(void) 
     { 
     if ((current_iterator != data.end()) && 
      ((*current_iterator).second>0)) 
     { 
      ((*current_iterator).second)++; 
     } 
     } 
    }; 

正如你所看到的,我沒有使用map :: iterator,而是從std :: iterator繼承了一個,使得迭代器引用MyContainer本身而不是映射的值類型。我可以

MyContainer h; 

h.addDataPair(1, 3); 
h.addDataPair(2, 4); 
h.addDataPair(3, 0); 
h.addDataPair(7, 9); 
h.addDataPair(11, 2); 

for (MyContainer::iterator it=h.begin(); !it.isEnd(); ++it) 
{ 
    cout << (*it).first() << " " << (*it).second() << endl; 
} 

訪問所有元素有了這個念頭,每當迭代器循環,它會返回一個指涉的容器,所以我可以添加一些代碼(如運營商[],運營商++)來控制的行爲更新地圖元素。例如,在此代碼中,

void operator++(void) 

將忽略對不存在的鍵或值初始化爲零的元素的任何操作。但是,我仍然有一些疑問,我正在尋找您的建議

1)如果仔細閱讀代碼,您會看到我使用current_iterator來存儲當前的map :: iterator並使用end_iterator來存儲地圖的結束迭代器。當調用MyContainer.begin()時,這些迭代器將被設置。我需要end_iterator的原因是,如果我將current_iterator設置爲map.end(),那麼它將在循環過程中更改current_iterator。例如,下面的代碼將無法正常工作

iterator begin() 
{ 
    current_iterator = data.begin(); 
    return myiterator<MyContainer>(this); 
} 

iterator end() 
{ 
    current_iterator = data.end(); // here we set current_iterator as data.end(), but this will change the current iterator of data too 
    return myiterator<MyContainer>(this); 
} 

所以當你循環用下面的代碼的容器,將無法正常運行

for (MyContainer::iterator it=h.begin(); it!=h.end(); ++it) 
{ 
    cout << (*it).first() << " " << (*it).second() << endl; 
} 

這就是爲什麼我寫了isEnd()函數在迭代器中。但是這看起來並不優雅,有什麼更好的想法來解決這個問題?

2)爲「有限」 ++操作,如果我們從容器修改地圖要素如下,不用任何問題

// assuming the map initially contains (2, 4), (3, 0), (7, 9), (11, 2) 

h[4]++; // modify the element with key==4, won't do anything, no such key 
h[3]++; // modify the element with key==3, won't do anything, value=0 
h[11]++; // modify the element with key==11, then we have (11, 3) 
(*(h.begin()))++; // modify the first element, works, we have (2,5) 

但是,如果你修改了在遍歷所有元素中,循環將永遠不會結束,爲什麼這

for (MyContainer::iterator it=h.begin(); !it.isEnd(); ++it) 
{ 
    (*it)++; // it works 
    (*it)[3]++; // it will cause the loop run and never stop 
    cout << (*it).first() << " " << (*it).second() << endl; 
} 

任何想法?

+0

爲什麼不使用count(key)方法? – 2012-04-19 22:53:14

+0

是的,在我的原始代碼中,我也嘗試count(key),但在此之後,我添加了更多的訪問地圖控件的控件(++操作就是我上面展示的示例)。所以如果我不寫一個單獨處理所有這些限制的類,那麼代碼就變得非常混亂和錯誤。我花了幾天來調試代碼,因爲map :: find()或map :: count太多了,所以我開始編寫一個包裝器。 – user1285419 2012-04-19 22:59:16

回答

1

但是,如果你修改了在遍歷所有元素,循環將永遠不會結束,那是什麼

那就不要,而不是建立對象的列表中刪除,然後在循環之後將其刪除。