自定义迭代器操作符重载

Custom iterator operator overloading

本文关键字:重载 操作符 迭代器 自定义      更新时间:2023-10-16

我正在尝试实现自定义迭代器的->操作符。然而,我不知道如何精确地定义它们。

我的Iterator类和MapNode定义如下:

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

现在我想重载操作符->,但问题是我不知道如何返回迭代器当前指向的键和值对的指针:

我当前的实现是:

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

但是我担心这会导致内存泄漏,因为ValueType指针内存永远不会被释放。

有人能指导我如何正确地做到这一点吗?

请帮助。

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

我将首先在std::pair中的MapNode中存储值:

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

则迭代器只能返回该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));
}

强制转换有点难看,但这就是为什么要将它封装在一段代码中,您几乎不需要看。

如果您真正担心的是潜在的内存泄漏,您可以将unique_ptr返回给pair。这将确保当new 'd对不再被引用时,它将被删除。

语法为:

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

或者,由于std::pair可以复制,如果Key_TMapped_T的类型也可能是可复制的,则可以按值返回pair .

根据Key_TMapped_T的可能类型,在像这样的模板代码中使用pair时,需要注意这些类型是否是引用。会引起头痛。

参见:std::pair引用

如果你真的真的想要返回一个指针你可以做这样的事情:

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

但是你很可能会后悔的。

您必须编写一个包装器,例如

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

,迭代器变成:

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;
};
演示