2012-04-19 9 views
1

私はアルゴリズムのデータホルダーとしてstd :: mapを使用していますが、なんらかの理由で何らかの方法でマップ要素のアクセスを制御する必要があります。演算子[key]を直接呼び出すことによってマップの要素にアクセスできることがわかります。ただし、キーが存在しない場合は、演算子[key]を呼び出すたびに自動的に 'ゼロ'として初期化された値を持つキーが作成されます。しかし、私のアルゴリズムでは、存在するキーと値が非ゼロのときにのみ要素を変更できるという制限によってアクセスを制御します。たとえば、マップに次の要素(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を使用する代わりに、イテレータがマップの値型ではなくMyContainer自体を参照するように、std :: iteratorから継承します。私は、このアイデアで

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が変更されるということです。たとえば、次のコードは、次のコードでコンテナが、それは私がisEnd()関数を書く理由だと正しく

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

を実行しないとき、あなたループ

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); 
} 

ので動作しません。代わりにイテレータでしかし、これは優雅に見えません、これを回避するための良いアイデアですか? 「限られた」++の操作のための

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

なぜカウント(キー)メソッドを使用しないのですか? –

+0

はい、私の元のコードでは、私もcount(キー)を試していますが、その後、私はマップコントロールへのアクセスのコントロールを追加します(++操作は上記の例です)。したがって、これらの制限をすべて個別に処理するクラスを作成しないと、コードが非常に乱雑になってしまいます。非常に多くのmap :: find()またはmap :: countがあるので、私はコードをデバッグするのに数日を費やしています。そのため、代わりにラッパーを書くことができます。 – user1285419

答えて

1

しかし、あなたは

はその後、代わりに、ループ後にそれらを削除し、削除するオブジェクトのリストを作成していないことを何、すべての要素を反復しながら、ループが終了しないことを変更した場合。

関連する問題