1

I'm implementing a custom container with an STL-like interface for a 3D grid control for my scientific software. This is my second question regarding the iterator class for this container. Thanks for helping me with the first!

My question is just like "How do you avoid code duplication when implementing const and non-const iterators?". I just wanted to ask if it is possible to provide a template-less solution? (And without providing a second const iterator class!)

The iterator class looks like this:


class spGridIterator {
public:
    typedef forward_iterator_tag iterator_category;
    typedef spGridNode value_type;
    typedef int difference_type;
    typedef spGridNode* pointer;
    typedef spGridNode& reference;

    spGridIterator();
    spGridIterator(spGrid* gr, int index);
    spGridIterator(const spGridIterator& orig);
    virtual ~spGridIterator();

    // STL-ные операторы итератора
    bool operator == ( const spGridIterator& hs ) const {
        return (m_grid == hs.m_grid) && (m_idx == hs.m_idx);
    }

    bool operator != ( const spGridIterator& hs ) const {
        return (m_grid != hs.m_grid) || (m_idx != hs.m_idx);
    }

    // non-const operators
    spGridIterator& operator++();
    spGridIterator& operator++(int);

    reference operator*() const;
    pointer operator->() const { return &(operator*()); }

private:
    spGrid* m_grid;
    int m_idx;
};

And an implementation...

spGridIterator::spGridIterator(spGrid* gr, int index) {
    m_grid = gr;
    m_idx  = index;
}

spGridIterator& spGridIterator::operator++()
{
    int last = m_grid->numpoints;

    if (m_idx < last) {
        m_idx++;
    }
    return *this;
}

spGridIterator& spGridIterator::operator++(int) {
    return operator++();
}

spGridIterator::reference spGridIterator::operator*() const {
    return ( m_grid->GetNode(m_idx) );
}

I checked the doctor dobbs article about custom iterator implementation. They suggest implementing an iterator class template and adding an additional template parameter for the value_type.

Well, the second solution is to provide a regular iterator and a const iterator classes.

Is there third, maybe "kinda hacky", single class template-less solution? Maybe providing a conversion operator or an additional const version of operator++()?

Thanks, Ilya

Community
  • 1
  • 1
ezpresso
  • 7,896
  • 13
  • 62
  • 94
  • Your `operator++(int)` returns the wrong value - it's postfix `++`, so it should return a copy of the iterator *prior* to being incremented, not a reference to the iterator *after* being iterated. Canonical implementation is `Iterator Iterator::operator++(int) { Iterator old = *this; ++(*this); return old; }` – Steve Jessop Oct 31 '10 at 18:35
  • I've got it! Thanks for a valuable comment! – ezpresso Oct 31 '10 at 18:56
  • I not really needed I would not implement the postfix ++ operator. You really want to encourage people using the prefix ++ operator instead of the postfix ++ operator. – Patrick Oct 31 '10 at 19:44
  • 1
    @Patrick: good idea, but if it doesn't have postfix ++ then it isn't an iterator, according to the standard. – Steve Jessop Nov 01 '10 at 13:29

1 Answers1

3

If you want to go kind of hacky, you may be able to abuse "const_cast" to create a const iterator out of a non-const one.

Michael Goldshteyn
  • 71,784
  • 24
  • 131
  • 181
  • Simple trick, but it works. Don't forget to clearly comment in the source code why you are abusing the const_cast. Otherwise, the next developer reading the code will think that you made a mistake and will want to correct your error, euh trick. – Patrick Oct 31 '10 at 19:43