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.
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;
};
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.