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. Ifmember
isn't a field/member of the class/struct pointed to be the return ofoperator ->
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 sayreturn_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;
}
精彩评论