如何在Foo的向量中使用Foo *迭代器?

时间:2010-05-27 22:46:17

标签: c++ iterator

如果我有一个包含std::list<Foo>并且具有公共方法begin()end()的类来返回该列表的迭代器,那么如何实现其他方法来将迭代器返回到std::list<Foo*>,最好不使用boost?

我宁愿不维护指针的并行容器。

修改

我有一个很大的代码库,我想改进。它有一个树状数据结构,其基类有一个返回对象子节点的方法:

class FooBase
{
    // ...
    virtual bool getChildren(std::vector<FooBase *>& children);
    virtual size_t getChildrenCount() const { return 0; };
    // ...
}

有一个模板化的类实现了子对象的集合:

template <class T>
class FooCollection: public FooBase
{
public:
    typedef typename std::list<T> ContainerType;
    typedef typename ContainerType::iterator iterator;
    typedef typename ContainerType::const_iterator const_iterator;
private:
    ContainerType _items;
public:
    // ...
    const_iterator begin() const { return itemsM.begin(); };
    const_iterator end() const { return itemsM.end(); };
    iterator begin() { return itemsM.begin(); };
    iterator end() { return itemsM.end(); };

    virtual bool getChildren(std::vector<FooBase *>& children)
    {
        for (iterator it = itemsM.begin(); it != itemsM.end(); ++it)
            children.push_back(&(*it));
        return (itemsM.size() != 0);
    };
    // ...
};

代码使用不同FooCollection<>类提供的迭代器(类已知的位置),以及迭代树时的FooBase::getChildren()。我以为FooBase::getChildren()可以用迭代器替换,但也许我错了?

4 个答案:

答案 0 :(得分:3)

如何编写如下所示的简单迭代器类并使用它

class myIterator : std::iterator<std::list<Foo>::iterator::iterator_category
                               , Foo*, std::list<Foo>::iterator::distance_type
                               , Foo**, Foo*&>
{
public:
    myIterator(const std::list<Foo>::iterator& lIt) : it(lIt) {}
    myIterator(const myIterator& myIt) : it(myIt.it) {}
    myIterator& operator++() {++it;return *this;}
    myIterator operator++(int)
    {
        myIterator copy(*this);
        ++it;
        return copy;
    }
    myIterator& operator--() {--it;return *this;}
    myIterator operator--(int)
    {
        myIterator copy(*this);
        --it;
        return copy;
    }
    bool operator==(const myIterator& rhs) {return it==rhs.it;}
    bool operator!=(const myIterator& rhs) {return it!=rhs.it;}
    Foo* operator*() {return &(*it);}
private:
    std::list<Foo>::iterator it;
};

答案 1 :(得分:2)

std::list<Foo>::iterator的dereference运算符重载返回对相应Foo对象的引用。因此,如果您想要Foo对象std::list<Foo>::iterator上的it对象的地址,那么您可以使用&*it,其类型为Foo*

如果您确实需要一个可递增的迭代器而不是指针,那么您可以编写一个迭代器类来存储std::list<Foo>::iterator成员,比如说it,在取消引用时返回&*it。请注意,这样的迭代器类只能满足const迭代器的概念,因为&*it是一个r值。

答案 2 :(得分:2)

这个结构将有所帮助。它修改迭代器,以便取消引用它返回指针而不是引用:

struct PointerInstead : public list<Foo>::iterator {
  PointerInstead(const list<Foo>::iterator &x) : list<Foo>::iterator(x) { }
  Foo * operator * () const {
    Foo &f = *(*( (list<Foo>::iterator *) (this) ));
    return &f;
  }
};

以下是其使用示例:

  for(PointerInstead i = l.begin(); i != l.end(); i++)  {
    cout << i->first << '\t' << i->second << endl;
    printf("%p\n", (*i));
  }

然后你可以编写一个返回类似PointerInstead(this-&gt; begin())的pointerBegin()方法。

答案 3 :(得分:1)

可以创建一个或多个指向Foo std::list<Foo>元素指针的容器,但它将不可靠。问题是该列表拥有Foo个项目(它是一个副本),并且允许在未经批准的情况下更改这些项目的位置。因此,如果您有一个指向列表中第3个元素的指针,则列表可以移动元素,并且您的指针将无效(在您不知情的情况下)。

更好的解决方案是动态分配Foo项并将智能指针存储在不同的列表中。这允许您按不同的键排序项目。例如,您可以按Foo中的第一个字段排序 list1 ,并按Foo中的第3个字段排序另一个列表。

你必须提出自定义排序仿函数,因为默认操作是按智能指针的值排序,这是没人真正想要的。