1

I am trying to implement -> operator of a custom Iterator. However I am not getting how to define them precisely.

My Iterator class and MapNode are defined like:

template <typename Key_T,typename Mapped_T>
class Map<Key_T,Mapped_T>::Iterator
{
    MapNode<Key_T,Mapped_T>* curr;
}

template <typename Key_T,typename Mapped_T>
class MapNode
{
    Key_T key;
    Mapped_T value;
    MapNode *up,*down,*prev,*next;
    friend class Map<Key_T,Mapped_T>;
};

Now I want to overload operator->, but the problem is I am not exactly getting how to return pointer of pair of key and value where iterator is currently pointing:

My current implementation is :

template <typename Key_T,typename Mapped_T>
std::pair<const Key_T, Mapped_T>*
Map<Key_T,Mapped_T>::Iterator::operator->() const
{
    const Key_T currKey = (this->curr)->key;
    const Mapped_T currVal = (this->curr)->value;

    ValueType* vt = new ValueType(std::make_pair(currKey,currVal));

    return vt;
}

But I am afraid that this will cause memory leaks as the ValueType pointer memory won't be deallocated ever.

Can someone guide me on how can this be done correctly?

Please help.

[ValueType is defined as std::pair<const Key_T, Mapped_T>]

3 Answers 3

1

I would start by storing the values in the MapNode in an std::pair:

template <typename Key_T,typename Mapped_T>
class MapNode
{
    std::pair<Key_T, Mapped_T> value;
    MapNode *up,*down,*prev,*next;
    friend class Map<Key_T,Mapped_T>;
};

Then the iterator can just return the address of that pair.

template <typename Key_T,typename Mapped_T>
std::pair<const Key_T, Mapped_T> *
Map<Key_T,Mapped_T>::Iterator::operator->() const
{
    using ptr = std::pair<const Key_T, Mapped_T> *;
    return (ptr)(&(curr->value));
}

The cast is a little ugly, but that's why you encapsulate it inside a piece of code you rarely have to look at.

Sign up to request clarification or add additional context in comments.

Comments

0

If what you are really worried about is the potential for leaking memory, you could just return a unique_ptr to the pair. This will ensure that the new'd pair will be deleted whenever it is no longer referenced.

The syntax would be:

template <typename Key_T,typename Mapped_T>
std::unique_ptr<std::pair<const Key_T, Mapped_T>>
Map<Key_T,Mapped_T>::Iterator::operator->() const
{
    const Key_T currKey = (this->curr)->key;
    const Mapped_T currVal = (this->curr)->value;

    return std::make_unique<ValueType>(std::make_pair(currKey,currVal));
}

Alternatively since std::pair can be copied you could just return the pair by value if the types of Key_T and Mapped_T are likely to be copyable also..

Depending on the possible types of Key_T and Mapped_T you need to be careful about those types being references when using pair in template code like this. Can cause headaches.

See: std::pair of references

If you really really really want to return a pointer to something you can do something like this really hacky thing:

template <typename T> class myIterator {
  T m_current;
public:
  bool next() { move_to_next(m_current); } // Or however you increment.
  T& read() { m_current; }
};

But you will likely end up regretting it.

Comments

0

You have to write a wrapper, something like

template <typename Key, typename Value>
struct Wrapper
{
    std::pair<const Key&, Value>* operator -> () { return &p; }

    std::pair<const Key&, Value> p;   
};

and your iterator becomes:

template <typename Key_T,typename Mapped_T>
class Map<Key_T,Mapped_T>::Iterator
{
public:
    // ...

    Wrapper<Key_T, Mapped_T> operator->() const { return {{curr->key, curr->value}}; }
private:
    MapNode<Key_T,Mapped_T>* curr;
};

Demo

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.