implementing a C++ postfix increment operator

2019-06-25 08:38发布

I compiled the following example:

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

from cplusplus.com/reference and I get the compiler warning:

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

What's wrong here? Is the postfix signature supposed to be myiterator operator++(int) i.e. return by value?

Is there somewhere defined what the postfix signature should look like on STL iterators?

4条回答
Fickle 薄情
2楼-- · 2019-06-25 08:45

You don't want to return the reference: by doing so, you're returning a reference to a variable that, by the time the function has returned, no longer exists. All you need is:

myiterator operator++(int) {myiterator tmp(*this); operator++(); return tmp;}
查看更多
Fickle 薄情
3楼-- · 2019-06-25 08:48

Is there somewhere defined what the postfix signature should look like on STL iterators?

The Standard.

The Standard dictates such things. In the case of this operation, the standard basically says "you have to return something that is convertible to const X&" where X is the iterator. In practice, this means you can return by reference if that applies to you (it doesn't), or return by value.

See 24.1.3/1

查看更多
在下西门庆
4楼-- · 2019-06-25 08:48

you're returning a reference to a variable that gets destroyed when the method exits. the compiler is warning you of the consequences of this. by the time the reference is received by the caller, the variable it references no longer exists.

查看更多
冷血范
5楼-- · 2019-06-25 09:06

This line:

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

Should be:

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.

As a side note:

You don't actually need the copy constructor:

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

The compiler generated version will work perfectly (as the rule of three/four does not apply as you do not own the RAW pointer contained by your class).

Your comparison operators should probably be marked as const and I personally prefer to define the != operator in terms of the the == operator and let the compiler optimize away any ineffecency (though this is just a personal thing).

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

The operator * should probably have two versions. A normal and a const version.

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

As a last note: A pointer by itself Is an iterator. SO you don't actually need to wrap pointers to make them iterators they will behave correctly as iterators (and not just input iterators but random access iterators).

查看更多
登录 后发表回答