реализация постфиксного оператора приращения C ++ - PullRequest
4 голосов
/ 03 декабря 2010

Я скомпилировал следующий пример:

#include <iostream>
#include <iterator>
using namespace std;

class myiterator : public iterator<input_iterator_tag, int>
{
  int* p;
public:
  myiterator(int* x) :p(x) {}
  myiterator(const myiterator& mit) : p(mit.p) {}
  myiterator& operator++() {++p;return *this;}
  myiterator& operator++(int) {myiterator tmp(*this); operator++(); return tmp;}
  bool operator==(const myiterator& rhs) {return p==rhs.p;}
  bool operator!=(const myiterator& rhs) {return p!=rhs.p;}
  int& operator*() {return *p;}
};

int main () {
  int numbers[]={10,20,30,40,50};
  myiterator beginning(numbers);
  myiterator end(numbers+5);
  for (myiterator it=beginning; it!=end; it++)
      cout << *it << " ";
  cout << endl;

  return 0;
}

из cplusplus.com / reference и получил предупреждение компилятора:

iterator.cpp: In member function 'myiterator& myiterator::operator++(int)':
iterator.cpp:13: warning: reference to local variable 'tmp' returned

Что здесь не так?Предполагается, что сигнатура постфикса должна быть myiterator operator++(int), то есть возвращаемая по значению?

Где-то определено, как должна выглядеть сигнатура постфикса на итераторах STL?

Ответы [ 4 ]

5 голосов
/ 03 декабря 2010

Где-нибудь определено, как должна выглядеть подпись постфикса на итераторах STL?

Стандарт.

Стандарт диктует такие вещи. В случае этой операции стандарт в основном гласит: «Вы должны вернуть что-то, что можно преобразовать в const X&», где X - итератор. На практике это означает, что вы можете вернуться по ссылке, если это относится к вам (это не относится), или вернуть по значению.

См. 24.1.3 / 1

3 голосов
/ 03 декабря 2010

Вы не хотите возвращать ссылку: тем самым вы возвращаете ссылку на переменную, которая к моменту возврата функции больше не существует. Все, что вам нужно, это:

myiterator operator++(int) {myiterator tmp(*this); operator++(); return tmp;}
2 голосов
/ 03 декабря 2010

Эта строка:

myiterator& operator++(int) {myiterator tmp(*this); operator++(); return tmp;}

Должно быть:

myiterator  operator++(int) {myiterator tmp(*this); operator++(); return tmp;}
//      ^^^^ Not return by reference.
//           Don't worry the cost is practically nothing for your class
//           And will probably be optimized into copying the pointer back.

В качестве примечания:

На самом деле вам не нужен конструктор копирования:

myiterator(const myiterator& mit) : p(mit.p) {}

Версия, сгенерированная компилятором, будет работать отлично (правило трех / четырех не применяется, поскольку у вас нет указателя RAW, содержащегося в вашем классе).

Ваши операторы сравнения, вероятно, должны быть помечены как const, и я лично предпочитаю определять оператор! = В терминах оператора == и позволить компилятору оптимизировать любую неэффективность (хотя это всего лишь личное). *

bool operator==(const myiterator& rhs) const {return p==rhs.p;}
bool operator!=(const myiterator& rhs) const {return !(*this == rhs);}
                            //        ^^^^^^^ Added const

Оператор *, вероятно, должен иметь две версии. Обычная и постоянная версия.

int&       operator*()       {return *p;}
int const& operator*() const {return *p;}

В качестве последнего примечания: указатель сам по себе является итератором. Так что на самом деле вам не нужно оборачивать указатели, чтобы сделать их итераторами, они будут правильно работать как итераторы (и не только входные итераторы, но итераторы с произвольным доступом).

0 голосов
/ 03 декабря 2010

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

...