C ++ Ошибка с оператором * в пользовательском итераторе для b-дерева - PullRequest
1 голос
/ 17 октября 2011

Я получаю следующую ошибку при попытке вернуть значение с помощью оператора * () в моем настраиваемом итераторе.

 error: invalid initialization of non-const reference of type 'char&' from a temporary of type 'char'

Если кто-нибудь сможет мне помочь, это было бы здорово!

Особенности кода следующие:

Код теста:

  for(btree<char>::iterator itr = tree.begin(); itr != tree.end(); ++itr) {

    cout << *itr << " "; // <- this line complains about the * operator.
  }

Код оператора * ():

template <typename T> typename btree_iterator<T>::reference btree_iterator<T>::operator*() const {

  return pointee_->value(); // <- this line is where the error above is produced from.
}

pointee_из класса btree_iterator является закрытой переменной, определяемой следующим образом:

btree_node<T>* pointee_;

ссылка является typefef'ed следующим образом в классе btree_iterator:

  typedef T&       reference;

value () определяется вКласс btree_node следующим образом:

T value() const;

// function definition.
template <typename T> T btree_node<T>::value() const { return value_; }

значение изначально сохраняется в btree_node через его конструктор следующим образом:

template <typename T> btree_node<T>::btree_node(const T& elem) : value_(elem), nextCont_(NULL), prevCont_(NULL), nextNode_(NULL), prevNode_(NULL) {}

Пожалуйста, дайте мне знать, если я пропустил, включая любую важную информацию, и извиненияесли я это сделал!

Судя по ошибке, похоже, что я пытаюсь вернуть ссылку на локальную переменную.Сам итератор может быть локальным, но возвращаемое им значение не должно быть, поскольку конструктор узла изначально получает ссылку и сохраняет ее в узле.

Заранее спасибо и с уважением!

Ответы [ 2 ]

3 голосов
/ 17 октября 2011

Вы пытаетесь использовать ссылку на временную переменную

template <typename T> T btree_node<T>::value() const { return value_; }
                     ^^^

Возвращает временную копию value_.

template <typename T> typename btree_iterator<T>::reference btree_iterator<T>::operator*() const {
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  return pointee_->value(); // <- this line is where the error above is produced from.
}

Возвращает ссылку на эту временную копиюкопия.Скорее всего, вы хотите, чтобы value() вернул ссылку, но это зависит от вас - ссылка позволяет клиентам вашего btree изменять содержимое.Особенно, если дерево упорядочено по значению узла, вы можете не захотеть этого делать.Подумайте, как это относится к вашему дизайну.

1 голос
/ 17 октября 2011

pointee_->value() возвращает значения, которые в основном являются свежей копией. Следовательно, это значение локально в operator*, и вы не можете вернуть ссылку на него.

Я бы порекомендовал сделать это так же, как это делают большинство контейнеров, т. Е. Имеющие оба, iterator и const_iterator, тогда как const_iterator возвращает ссылку на const, а итератор возвращает ссылку. Тот же принцип применяется к value(). Есть версии, возвращающие ref и const ref.

Если вы когда-нибудь захотите поработать с копиями, вы можете создать их по ссылке в коде клиента. Если вы не хотите разрешать изменение значений, просто отбросьте (или сделайте приватными, или что-то еще) неконстантными частями. Он также соответствует ожиданиям людей, использующих ваше btree:

Итераторы не делают копии где-то, но вы перебираете данные внутри структуры данных. Если вам нужны копии, вы можете сделать их.

...