Baltram
Baltram

Reputation: 681

How to construct a custom const_iterator with const data?

I'm writing the iterator classes for a custom container (some hash map class), let's call this container Map.

For a couple of reasons it seems handy to derive iterator from const_iterator and I already did this in some other custom container (an array class), which works great, so I want to stick to this pattern.

But now that leads to the following problem (which is quite general/abstract, I'm sorry):

Whatever const_iterator's critical data member is (it might be a Map reference, or a pointer to Map::Elements, many ways are possible), it needs to be non-const so both const_iterator and the derived iterator can utilize it meaningfully in their methods.

But how can this non-const data member, in a proper way, be initialized when dealing with a const Map object (e.g. calling the method const_iterator Map::Begin( void ) const)?


To illustrate my question bit, I wrote some example code that solves the problem by using const_cast which, I suppose, is bad style:

#include <vector>

template< typename K, typename T >
class Map
{
public:
    class const_iterator
    {
    public:
        const_iterator( Map const & a_Map, int a_Index ) : 
            m_Index( a_Index ),
            m_Map( const_cast< Map & >( a_Map ) )  // Note the use of const_cast
        {
        }
    private:
        Map & m_Map;
        int   m_Index;
    };
    class iterator : public const_iterator
    {
    public:
        T & operator * ( void )
        {
            return m_Map.mElements[ m_Index ];
        }
    };
public:
    const_iterator Begin( void ) const { return const_iterator( *this, 0 ); }
    iterator       Begin( void )       { return       iterator( *this, 0 ); }
private:
    std::vector< T > m_Elements;
};

Upvotes: 2

Views: 1055

Answers (1)

user1084944
user1084944

Reputation:

When I played with this in the past, I convinced myself that inheritance wasn't a good idea. While iterator and const_iterator might share a lot of code, they don't really share much in their interface.

Instead, I used templates to get the code reuse, so that iterator and const_iterator are just two versions of the same template. Provide an appropriate implicit conversion operator.

But if you insist on the inheritance model, and don't want your iterator to have its own non-const reference (i.e. its constructor initializes both its non-const version and the base class's const version), then const_cast is the only real option, I think.

Upvotes: 2

Related Questions