开发者

Semantics of pointer dereference operator `->`

I am looking for some help regarding the pointer dereference operator -> . Let me describe what I am trying to do.

I am implementing a unidirectional iterator for a special container. The container is special in the sense that it does not physically allocate any space for th开发者_开发知识库e contained values but generates them at run time on demand. For example, consider that the container is "M consecutive integral multiples of N".

Since I do not want to store the value directly in my iterator, I create a value on the heap on demand.

When I need a pointer to the value I delete the old one if it's out-of-date and create a new one. This means that invocation of operator *() or operator ->() may delete an old value and new a new value, if the iterator has been advanced with operator ++() after they were last invoked.

Now I would like to use a smart_ptr to point at my value rather than keep a native pointer around. In order to do so I realize I need to understand the semantics of the -> operator better.

  • First of all, is -> a unary operator ?
  • If that be so, how does i->member work. This would translate to (pointer returned)member, which is not a syntactically valid form.
  • "member" could be a data member or a member function.
  • ->() smells more like a binary operator that executes (*pointer returned).member. Since "member" is not a value, such a semantics is not equivalent to a binary operator either.
  • What happens to the pointer returned by ->() ? who is supposed to own it ?
  • How can I use RAAI in this framework ? Is reference counted pointers the only option ?
  • There is no -- operator for this iterator so i don't need to keep the previous values around

Thanks for your responses. Ending with a meta question, should this be a wiki ?


Here is the answer to answer your questions, though I do not think they are so useful as you might hope:

  • Yes, it is a unary operator
  • No, it does not care what member is. If member isn't a field/member of the class/struct pointed to be the return of operator -> then the compiler will complain.
  • member could indeed be either a data member or a member function.
  • No, it's a unary operator since it does nothing whatsoever with member. It's there just to implement smart pointers. It is perfectly valid to say return_type *ptr = smarptr.operator ->().
  • It's owned by whatever returns it. But this is purely by convention. You can decide whatever you want. But if you decide anything other than that it will surprise a whole ton of people to the point they will think they have a bug in their program and will never think to wonder if your smart pointer implementation has some bizarre semantics nobody else uses.
  • If you use operator -> for anything at all other than implementing a smart pointer I have no intentions of helping you write code that programmers after you will revile and make fun of.
  • This is a statement, not a question, so I have no answer for it. :-)

I question your desire to point at your value. It seems to me like you could hold it by value as a member value of your iterator, and I will give an example of how this could work below. But if you're set on using a pointer to your value, and want to use a smart pointer, just return the result of smartptr.operator ->() for your own operator ->(). You might also use the member function of your smart pointer (often get) that returns a 'bare' pointer and that would likely confuse people a little less.

Here is a sample of how your example container should work:

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


You probably don't need to "create a value on the heap". At least for numbers, just let the iterator contain the iteration state directly.


Much of it is answered by others. I'd still like to share how -> operator overloading works.

When we do pA->Function(), something like this happens behind the scenes (pA.operator->())->Function()

In RAII framework, the pointer class needs to behave as if it were an actual pointer. So one needs to overload the arrow -> operator.

e.g. of an overloaded -> operator in RAII.

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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜