user1285419
user1285419

Reputation: 2225

looking for a way to customize an iterator on std::map

I am using a std::map in my code to store data. It is quite easy to access and/or modify the elements with iterator of the map but since I really need to suppress some operations (like ++, [], etc.) I don't know if it is true, but seems few articles recommend not to inherit the std::map directly so I am writing a wrapper instead.

class MyContainer
{
  private:
    std::map<int, int> data;

  public:
    int &operator[](int); // here we write the interface to control the behavior of accessing the data element
    void &operator++();
    void &operator--();
};

But this cause another issue. Actually, I am using iterator everywhere in the code to access/modify the elements. But after the map moved into the self-defined class, I can no longer use the iterator in the main program to handle the data. Someone recommend to write my own iterator but after reading several articles, it seems that people suggest to customize our own iterator by inheriting std::iterator. It seems straightforward but it still too abstract to me. I have two doubts

1) I am going to iterate map but my wrapper is not really a container. and to control the behavior of the following operations (++, --, []) on the map elements, I should have the self-defined iterator refer to MyContainer instead of map. It seems confusing to me because we need to advance map but the iterator refer to the wrapper instead. I don't know how to make it work, is there any example I can follow for similar case? Thanks.

2) I don't want the code to access the map element directly, hence, I have defined the operator in the wrapper as

int &operator[](int)

In above function, the returned reference depends on the input parameter, that is to say, for some cases, it could return a NULL reference instead of something refer to the element. But if a NULL returned, the following calling is no longer valid

data[3]++;

because data[3] could return a null reference. But how can I check if the returned reference is null or not before updating the element?

Upvotes: 1

Views: 1400

Answers (2)

juanchopanza
juanchopanza

Reputation: 227578

I think implementing special behaviour for the elements' ++ operators and so on is overkill. Likewise for the increment and decrement operations on the iterators. I think a good solution is simply to add bound checking to the [] accessors and throw an out of bounds exception when necessary. So, use the map's begin() and end() methods, and add bound checking to []:

class MyContainer
{
  private:
    std::map<int, int> data;
  public:
    typedef std::map<int, int> MapType;
    typedef MapType::iterator iterator;
    typedef MapType::const_iterator const_iterator;
    typedef MapType::reference reference;
  public:
    iterator begin() {return data.begin();}
    const_iterator begin() const { return data.begin();}
    // and so on ...
    reference operator[](size_t i) {
      if (data.size()<=i) { /* raise exception here */ }
      return data[i];
    }
    const reference operator[](int) const { /* same as above */}

};

This has the advantage that the return types match those of standard library containers.

Upvotes: 3

wuliang
wuliang

Reputation: 749

You can make you "map" public, if you have need to iterate it. Otherwise, don't provide the interface of iteration, do everything (which needs iteration) inside.

Upvotes: 0

Related Questions