Как получить итератор Foo * для вектора Foo? - PullRequest
1 голос
/ 28 мая 2010

Если у меня есть класс, содержащий std::list<Foo> и имеющий открытые методы begin() и end() для возврата итераторов для этого списка, как я могу реализовать дополнительные методы для возврата итераторов в std::list<Foo*>, предпочтительно используя повышение?

Я бы предпочел не поддерживать параллельный контейнер указателей.

Edit:

У меня большая база кода, которую я хочу улучшить. Он имеет древовидную структуру данных с базовым классом, в котором есть метод для возврата дочерних объектов объекта:

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 ]

3 голосов
/ 28 мая 2010

Как насчет написания простого класса итератора, как показано ниже, и его использования

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;
};
2 голосов
/ 28 мая 2010

Перегрузка оператора разыменования std::list<Foo>::iterator возвращает ссылку на соответствующий объект Foo. Следовательно, если вы хотите, чтобы адрес объекта Foo был std::list<Foo>::iterator object it, то вы можете использовать &*it, который имеет тип Foo*.

Если вам действительно нужен инкрементный итератор для указателей, то вы можете написать класс итератора, который хранит член std::list<Foo>::iterator, скажем it, возвращающий &*it при разыменовании. Обратите внимание, что такой класс итераторов может удовлетворять концепции const итератора только по той причине, что &*it является r-значением.

2 голосов
/ 28 мая 2010

Эта структура поможет. Он изменяет итератор так, что разыменование возвращает указатель вместо ссылки:

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

Затем вы можете написать метод pointerBegin (), который возвращает что-то вроде PointerInstead (this-> begin ()).

1 голос
/ 28 мая 2010

Получение коллекции или контейнеров указателей на элементы Foo в std::list<Foo> может быть создано, но это будет ненадежно. Проблема в том, что список владеет элементами Foo (он сделал копию), и разрешено изменять местоположение этих элементов без одобрения. Таким образом, если у вас есть указатель на третий элемент в списке, список может переместить элемент, и ваш указатель будет недействительным (без вашего ведома).

Лучшим решением является динамическое распределение элементов Foo и хранение умных указателей в разных списках. Это позволяет сортировать элементы по разным ключам. Например, вы можете отсортировать list1 по первому полю в Foo и другой список по 3-му полю в Foo.

Вам придется придумать пользовательскую сортировку функторов , поскольку операция по умолчанию будет сортировать по значению умного указателя, чего на самом деле никто не хочет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...