ratkke
ratkke

Reputation: 469

Implementation(overloading) of -> operator

i have hash-table, which i realising with 2d vector

std::vector<std::vector<std::string> > htable;

Also, i've wrote ++, -- and * operators in my myiterator class, which is subclass of my hash-table.

class myiterator{
    public:
        myiterator();
        myiterator(std::vector<std::vector<std::string> >& v, int ii, int jj) : 
            vec(v), i(ii), j(jj) {}
        std::string operator*(){
            return vec[i][j];
        }
        myiterator& operator++(){
            if(j==vec[i].size()-1){
                int start=0;
                while(vec[start].size()==0){
                    start++;
                }
                i=start;
                j=0;
            }
            else{
                j++;
            }
            return *this;
        }
        // myiterator operator++(int); // postfix operator
        myiterator& operator--(){
            if(j==0){
                int end=vec[i].size()-1;
                while(vec[end].size()==0){
                    end--;
                }
                i=end;
                j=vec[end].size()-1;
            }
            else{
                j--;
            }
            return *this;
        } // prefix operator
        // myiterator operator--(int); // postfix operator
        std::string* operator->();
    private:
        std::vector<std::vector<std::string> >& vec; // the vector we are iterating over
        int i; // the position in the vector (first dimension)
        int j; // the position in the vector (second dimension)
    };
    myiterator begin() {
        int start=0;
        while(htable[start].size()==0){
            start++;
        }
        return (myiterator(htable, start, 0));
    }
    myiterator end(){
        int end=htable.size()-1;
        while(htable[end].size()==0){
            end--;
        }
        return (myiterator(htable, end, htable[end].size()-1));
    }

The question is, how must i implement -> operator? And what does he do? I googled it, but i didn't understand. Sorry if my question is nooby and basic. Thanks in advance.

Upvotes: 0

Views: 114

Answers (3)

rabensky
rabensky

Reputation: 2934

John already answered your question about operator->. I just wanted to comment on the operator++ and operator--. I would have made a comment but this will be a bit long :)

Lets start from this:

    myiterator& operator++(){
        if(j==vec[i].size()-1){
            int start=0;
            while(vec[start].size()==0){
                start++;
            }
            i=start;
            j=0;
        }
        else{
            j++;
        }
        return *this;
    }

You have the line start=0. This means that every time you get to the end of an inner vector (j==vec[i].size()-1) you will start looking for the "next" vector from the start - and then probably get right back to the same vector you started from.

This is a relatively small bug (you should just set start=i+1 instead) but notice how you never check whether you're at the end of the outer vector either! Well, you're not supposed to do ++ on an iterator after the end, right? Actually, you ARE supposed to be able to get to 1 cell after the end! So that would be a problem here. You should be checking if i==vec.size() somewhere.

Finally - other than these two issues the code looks like it'll work - but it's cumbersome. It can be much simpler. How? Well, you have 2 different cases you split to from the beginning - checking if j==vec[i].size()-1. I see the logic - but try to think of it a bit differently. It is a well used idiom in c++ to go "one after the last element" to signal the end. You'll see in a sec how that's nicer here too. But the idiom - or the "well used" - way to check if you're at the end is j==vec[i].size() so when I see the size()-1 I immediately see "things can be simpler".

The other thing that tells me this could be simpler is that you have the same test in two different places: testing if there are no more elements in the current inner vector, so you can move to the next one. You do this both in the line

if (j==vec[i].size()-1)

and

while(vec[start].size()==0)

(you check if the current vector is empty, meaning it has no elements left - as it has no elements at all - and hence you move to the next one)

Both these things (checking twice and using size()-1) tell me this function can be simpler. Here's an example:

myiterator& operator++(){
  j++; // First I increase j! Why? Because I want to get to "one after end" if it's the end
  while(j==vec[i].size()){ // in "iterator speak" this is equivalent to "(j==i->end())"
    i++;
    if (i==vec.size()) // in "iterator speak" this is "i==vec.end()"
      break;
    j=0; // in "iterator speak" this is "j=i->begin()"
  }
  return *this;
}

This seems much shorter and more elegant, and especially it makes it easy to "see" the inner iterators if you ever choose to change i and j to iterators (meaning you won't need to keep the reference vec! Only i and j!)

Try making operator-- this way too, and if you really want a nice exercise to understand iterators - change like I suggested i and j to iterators themselves without having a reference vec at all and see if you can make it work :)

Upvotes: 1

goldcode
goldcode

Reputation: 653

Typically application would be to use the operator -> for smart pointer objects which return a pointer to the internal object. see usage

Upvotes: 0

john
john

Reputation: 87959

Looks good so far. I would say

    std::string* operator->(){
        return &vec[i][j];
    }

The odd thing about operator-> is that after calling a user defined operator-> the compiler will call operator-> again on whatever is returned. So your operator-> should return the address of the object you want to access.

Upvotes: 2

Related Questions