指针解引用运算符` - >`的语义

时间:2010-11-01 05:09:17

标签: c++

我正在寻找有关指针取消引用运算符 -> 的一些帮助。让我来描述我想要做的事情。

我正在为一个特殊的容器实现一个单向迭代器。容器是特殊的,因为它不会为包含的值物理分配任何空间,而是在运行时根据需要生成它们。例如,考虑容器是“ N连续的M个连续整数倍”

由于我不希望将值直接存储在迭代器中,因此我会根据需要在堆上创建一个值。

当我需要一个指向值的指针时,如果它已过时并删除了旧指针,则会删除旧指针。这意味着, operator *() operator ->() 的调用可能delete为旧值,new为新值,如果在最后一次调用迭代器之前,它已经使用operator ++()进行了推进。

现在我想使用 smart_ptr 指向我的值,而不是保留原生指针。为了做到这一点,我意识到我需要更好地理解 -> 运算符的语义。

  • 首先, -> 一元运营商?
  • 如果是这样, i->member 如何运作。这将转换为(pointer returned)member,这不是语法上有效的形式。
  • “member”可以是数据成员或成员函数。
  • ->() 闻起来更像是执行(*pointer returned).member的二元运算符。由于“member”不是值,因此这种语义也不等同于二元运算符。
  • ->()返回的指针会发生什么变化?谁应该拥有它?
  • 如何在此框架中使用RAAI?引用计数指针是唯一的选择吗?
  • 此迭代器没有--运算符,因此我不需要保留以前的值

感谢您的回复。结束元问题,这应该是一个维基吗?

3 个答案:

答案 0 :(得分:2)

这是回答你的问题的答案,尽管我认为它们并不像你希望的那样有用:

  • 是的,它是一元运算符
  • 不,它不关心member是什么。如果member不是类/结构的字段/成员,而是指向operator ->的返回,那么编译器会抱怨。
  • member确实可以是数据成员或成员函数。
  • 不,这是一个一元的运算符,因为它对member没有任何作用。它只是为了实现智能指针。说return_type *ptr = smarptr.operator ->()
  • 是完全有效的
  • 它归任何回报所有。但这纯粹是按照惯例。你可以决定你想要什么。但是如果你决定除此以外的任何东西,它会让很多人感到惊讶,他们会认为他们的程序中有一个错误,并且永远不会想到你的智能指针实现是否有其他人没有使用的奇怪语义。
  • 如果您使用operator ->除了实现智能指针之外的任何其他内容,我无意帮助您编写程序员编写代码后,您将辱骂和取笑。
  • 这是一个陈述,而不是一个问题,所以我没有答案。 : - )

我怀疑你想要指出自己的价值。在我看来,你可以将它作为迭代器的成员值保存它,我将举例说明它如何在下面工作。但是,如果您设置使用指向您的值的指针,并且想要使用智能指针,则只需为您自己的smartptr.operator ->()返回operator ->()的结果。您也可以使用智能指针的成员函数(通常为get),它返回一个“裸”指针,这可能会让人感到困惑。

以下是示例容器应如何工作的示例:

class multiples {
  public:
   multiples(int n, int starting_multiplier, int ending_multiplier)
      : n_(n), starting_(starting_multiplier), ending_(ending_multiplier)
   {
   }

   class const_iterator {
      friend class multiples;
     public:
      const int &operator *() const { return curval_; }
      const int *operator ->() const { return &curval_; }

      const const_iterator &operator ++() { curval_ += n_; return *this; }
      const const_iterator operator ++(int) {
         const_iterator tmp(*this);
         curval += n_;
         return tmp;
      }

      bool operator ==(const const_iterator &b) const { return curval_ == b.curval_; }
      bool operator !=(const const_iterator &b) const { return curval_ != b.curval_; }

     protected:
      explicit const_iterator(int n, int starting) : n_(n), curval_(starting * n) {}

     private:
      const int n_;
      int curval_;
   };

   const_iterator begin() const { return const_iterator(n_, starting_); }
   const_iterator end() const { return const_iterator(n_, ending_); }

  private:
   const int n_, starting_, ending_;
};

答案 1 :(得分:2)

您可能不需要“在堆上创建值”。至少对于数字,只需让迭代器直接包含迭代状态。

答案 2 :(得分:0)

其中很多都是由其他人回答的。我还是想分享一下 - >运算符重载工作。

当我们执行pA->Function()时,会发生类似这样的事情(pA.operator->())->Function()

在RAII框架中,指针类需要表现得好像它是一个实际的指针。因此,需要重载箭头->运算符。

e.g。重载 - > RAII中的运营商。

T* operator->()
{
return m_ptr;
}