51

I understand the normal operator overloading. Compiler can translate them to method call directly. I am not very clear about the -> operator. I was writing my first custom iterator and I felt like the need of -> operator. I took a look at the stl source code and implemented my own like it:

MyClass* MyClassIterator::operator->() const
{
    //m_iterator is a map<int, MyClass>::iterator in my code.
    return &(m_iterator->second);
}

Then I can use an instance of MyClassIterator like:

myClassIterator->APublicMethodInMyClass().

Looks like the compiler does two steps here. 1. Call the ->() method the get a temporary MyClass* variable. 2. Call the APublicMethodInMyClass on the temp variable use its -> operator.

Is my understanding correct?

nostalgk
  • 229
  • 2
  • 20
Ryan
  • 1,963
  • 3
  • 25
  • 35

2 Answers2

101

The operator-> has special semantics in the language in that, when overloaded, it reapplies itself to the result. While the rest of the operators are applied only once, operator-> will be applied by the compiler as many times as needed to get to a raw pointer and once more to access the memory referred by that pointer.

struct A { void foo(); };
struct B { A* operator->(); };
struct C { B operator->(); };
struct D { C operator->(); };
int main() {
   D d;
   d->foo();
}

In the previous example, in the expression d->foo() the compiler will take the object d and apply operator-> to it, which yields an object of type C, it will then reapply the operator to get an instance of B, reapply and get to A*, after which it will dereference the object and get to the pointed data.

d->foo();
// expands to:
// (*d.operator->().operator->().operator->()).foo();
//   D            C            B           A*
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • 1
    Can you point me to a reference on this? Can't seem to find any. Nobody else even mentions it. – Milind R Mar 01 '13 at 01:38
  • 11
    @MilindR: 13.5.6/1[...] *An expression x->m is interpreted as `(x.operator->())->m` for a class object x of type T if `T::operator->()` exists and if the operator is selected as the best match function by the overload resolution mechanism* If `x->operator->()` yields a pointer, it gets dereferenced, if it yields an object of a type that overloads `operator->()` that operator gets called. – David Rodríguez - dribeas Mar 01 '13 at 04:51
  • 1
    @MilindR: The accepted answer does say this, although it is not so explicit on the meaning: `myClassIterator.operator->()->APublicMethodInMyClass()` (second piece of code) – David Rodríguez - dribeas Mar 01 '13 at 15:26
  • @DavidRodríguez-dribeas: Yes, you can infer some recursion from the second line of accepted answer's code, but it is better explained in your answer (In fact, the recursion was not visible to me until I read yours). Thank you ! – Ad N Mar 10 '14 at 13:13
  • All this time I thought I had to manually write the recursion to fetch the pointer. +1 for the odd tidbit. – Thomas Eding Jul 23 '14 at 06:39
34
myClassIterator->APublicMethodInMyClass()

is nothing but the following:

myClassIterator.operator->()->APublicMethodInMyClass()

The first call to the overloaded operator-> gets you a pointer of some type which has an accessible (from your call-site) member function called APublicMethodInMyClass(). The usual function look-up rules are followed to resolve APublicMethodInMyClass(), of course, depending on whether it is a virtual or not.

There is not necessarily a temporary variable; the compiler may or may not copy the pointer returned by &(m_iterator->second). In all probability, this will be optimized away. No temporary objects of type MyClass will be created though.

The usual caveats also do apply to m_iterator -- make sure that your calls do not access an invalidated iterator (i.e. if you are using vector for example).

dirkgently
  • 108,024
  • 16
  • 131
  • 187