4

我整理了以下例子:实现C++后缀增量操作

#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迭代器上的样子?

+0

cplusplus.com是有用的,但不是权威的。在这种情况下,它会伤害你。如果你看一下实际的STL代码,你会发现迭代器经常被返回值,而cplusplus.com并没有告诉你可以这样做。 – 2010-12-03 16:39:28

+0

http://stackoverflow.com/questions/3181211/prefix-postfix-increment-operators – 2015-06-17 10:22:35

回答

5

是否有某处定义了postfix签名在STL迭代器上的样子?

该标准。

该标准规定了这样的事情。在这种操作的情况下,标准基本上说“你必须返回可兑换为const X&的东西”,其中X是迭代器。在实践中,这意味着您可以通过引用返回(如果这适用于您(不))或按值返回。

请参阅24.1.3/1

3

您不想返回引用:通过这样做,您将返回一个对该变量的引用,该变量在函数返回时不再存在。所有你需要的是:

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

+1这就是答案。我只补充说,错误消息告诉你到底是什么问题,对给定错误的逻辑解决方案实际上是正确的答案。按价值返回东西,而不是参考。 – 2010-12-03 16:37:41

+0

我知道。那是来自cplusplus.com的代码。我真的在寻找STL迭代器的后缀增量运算符的定义... – chris 2010-12-03 16:38:10

0

你正在返回一个变量的引用,当方法退出时它会被销毁。编译器正在警告你这样做的后果。到调用者接收到引用时,它引用的变量不再存在。

2

这条线:

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

编译器生成版本on将完美地工作(因为你不拥有你的类所包含的RAW指针,所以三/四的规则不适用)。

您的比较运算符应该被标记为const,我个人更喜欢用==运算符来定义!=运算符,并让编译器优化掉任何无效(尽管这只是个人的事情)。

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

运算符*应该可能有两个版本。一个正常和一个const版本。

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

作为最后一个音符:本身一个指针的迭代器。所以你实际上不需要包装指针来使它们成为迭代器,它们将作为迭代器正确运行(而不仅仅是输入迭代器,而是随机访问迭代器)。