简体   繁体   中英

Custom iterator operator overloading

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>]

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.

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM