【问题标题】:implementing a C++ postfix increment operator实现 C++ 后缀增量运算符
【发布时间】:2011-05-19 20:37:59
【问题描述】:

我编译了下面的例子:

#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 迭代器上的后缀签名应该是什么样的?

【问题讨论】:

  • cplusplus.com 很有用,但不权威。在这种情况下,它伤害了你。如果您查看实际的 STL 代码,您会发现迭代器通常是按值返回的,而 cplusplus.com 并没有告诉您可以这样做。

标签: c++ operator-overloading post-increment postfix-operator


【解决方案1】:

是否在某个地方定义了 STL 迭代器上的后缀签名应该是什么样的?

标准。

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

见 24.1.3/1

【讨论】:

  • 感谢您正确阅读问题并仅回答我正在寻找的问题。
【解决方案2】:

您不想返回引用:这样做是在返回对一个变量的引用,该变量在函数返回时已不存在。您只需要:

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

【讨论】:

  • +1 这就是答案。我只想补充一点,错误消息准确地告诉你问题是什么,给定错误的逻辑解决方案实际上是正确的答案。按值返回事物,而不是按引用。
  • 我知道。那是来自 cplusplus.com 的代码。我真的在寻找 STL 迭代器的后缀增量运算符的定义...
  • 我错过了我第一次阅读的链接。是的 - cplusplus.com 在这里是错误的。除了一些非常奇怪的情况外,以上将是后缀运算符的样子。没有规则说它不能返回引用 - 它通常不会,因为这样做是不合适的。
【解决方案3】:

这一行:

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

最后一点:指针本身迭代器。因此,您实际上不需要包装指针以使它们成为迭代器,它们将作为迭代器正常运行(不仅是输入迭代器,而且是随机访问迭代器)。

【讨论】:

    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-27
      • 2018-08-22
      • 1970-01-01
      相关资源
      最近更新 更多