Итератор STL: разыменование итератора на временный. Является ли это возможным? - PullRequest
5 голосов
/ 29 октября 2010

Я пишу трехмерную сетку для своего научного программного обеспечения, и мне нужно пройтись по узлам сетки, чтобы получить их координаты.Вместо того чтобы держать каждый объект узла в контейнере, я бы предпочел просто вычислять координаты на лету во время итерации.Проблема в том, что stl :: iterator требует возврата ссылки на значение в результате operator*() или указателя на operator->().

. Некоторый код ниже:


class spGridIterator {
public:
    typedef forward_iterator_tag iterator_category;
    typedef spVector3D value_type;
    typedef int difference_type;
    typedef spVector3D* pointer;
    typedef spVector3D& reference;

    spGridIterator(spGrid* gr, int index);

    spGridIterator& operator++();
    spGridIterator& operator++(int);

    reference operator*() const;
    pointer operator->() const;

private:
    spGrid* m_grid;
    int m_idx;
};

spGridIterator::reference spGridIterator::operator*() const {
    // return m_grid->GetPoint(m_idx);
}

spGridIterator::pointer spGridIterator::operator->() const {
    // return m_grid->GetPoint(m_idx);
}

Этот метод запрашивает координаты узла по предоставленному индексу


spVector3D spGrid::GetPoint(int idx) const {
    // spVector3D vec = ... calculate the coordinates here ...
    return vec;
}

Любой вклад в это?

Заранее спасибо, Илья

Ответы [ 4 ]

6 голосов
/ 29 октября 2010

Вы можете использовать переменную-член для хранения точки сетки, на которую она в данный момент указывает:

class spGridIterator {
public:
    typedef forward_iterator_tag iterator_category;
    typedef spVector3D value_type;
    typedef int difference_type;
    typedef spVector3D* pointer;
    typedef const spVector3D* const_pointer;
    typedef const spVector3D& const_reference;
    typedef spVector3D& reference;

    spGridIterator(spGrid* gr, int index);

    spGridIterator& operator++();
    spGridIterator& operator++(int);

    reference operator*();
    const_reference operator*() const;

    pointer operator->();
    const_pointer operator->() const;

private:
    spGrid* m_grid;
    int m_idx;
    mutable spVector3D CurrentPoint;
};

Тогда оператор разыменования может выглядеть так:

spGridIterator::const_reference spGridIterator::operator*() const {
    CurrentPoint = m_grid->GetPoint(m_idx);
    return CurrentPoint;
}

Спасибо @greg за указание, что CurrentPoint должно быть mutable, чтобы это работало. Это была бы ленивая реализация (извлекающая точку, только когда итератор фактически разыменован). Стремительная реализация обновит член CurrentPoint в методах мутатора итератора (варианты operator++ в этом примере), делая mutable лишним.

1 голос
/ 26 октября 2016

Я знаю, что этот пост слишком старый, но только потому, что у меня были те же "проблемы", и Google привел меня сюда, я добавлю свои два цента, вот что я нашел:

По крайней мере, в C ++В библиотеке есть много типов итераторов, каждый из которых объявляет некоторую связанную семантику.Типы:

  • Итераторы ввода
  • Прямые итераторы
  • Двунаправленные итераторы
  • Итераторы произвольного доступа
  • Итераторы вывода

В вашем проблемном случае подходит семантика входных итераторов.В частности, во входных итераторах operator*() не нужно возвращать ссылку на объект, он может даже возвращать вновь созданный объект.Таким образом, избегая наличия «фиктивного» объекта внутри объекта итератора, как предложил Бьорн.

Здесь вы можете посмотреть больше .

1 голос
/ 29 октября 2010

Краткий ответ: это приведет к неопределенному поведению, в конце концов, вы возвращаете ссылку на временный!Один из вариантов (если этот итератор не должен повторно входить - это иметь член класса (типа spVector3D), которому вы «назначаете» возвращаемое значение (конечно, вы можете сделать это более оптимально, передав ссылку на этоGetPoint, а также index), а затем верните его.

1 голос
/ 29 октября 2010

Поскольку итератор является объектом-значением, почему бы просто не установить для элемента значение, которое вы хотите вернуть, и вернуть ссылку на этот элемент?

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